This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
warning: returning reference to temporary
I am getting the error "returning reference to temporary" on the second line below.
class Object : public std::map <ExString, AnotherObject> const {
public:
const AnotherObject& Find (const ExString& string ) const {
Object::const_iterator it = find (string);
if (it == this->end()) { return AnotherObject() };
return ( it->second );
}
}
My class implements std::map.
I am new to C++ so I'm guessing its just a syntax error. Any help?
If your function looks like this:
AnotherObject& getAnotherObject()
{
. . .
Object::const_iterator it = find ("lang");
if (it == this->end()) { return AnotherObject() };
. . .
}
the problem is that the AnotherObject() you've returned will be destroyed as soon as the function exits, and so the caller to your function will have a reference to a bogus object.
If your function returned by value however:
AnotherObject getAnotherObject()
then a copy will be made before the original is destroyed and you'll be OK.
return AnotherObject(); creates an object which is destroyed before function exit - temporaries are destroyed at the end of the expression that contains them[*], and the expression AnotherObject() creates a temporary.
Since the function returns by reference, this means that by the caller even gets a chance to see that reference, it no longer refers to a valid object.
It would be OK if the function were to return by value, since the temporary would be copied[**].
[*] With a couple of situations that don't, but they don't help you here.
[**] Actually there's an optimization called "copy constructor elision" which means the temporary needn't be created, copied and destroyed. Instead, under certain conditions the compiler is allowed to just create the target of the copy in the same way it would have created the temporary, and not bother with the temporary at all.
You're creating a temporary value on the stack AnotherObject() and returning it right before it gets destroyed. Your function's caller would get garbage, and so it's forbidden.
Maybe you want to allocate it on the heap and return a pointer to it instead?
return new AnotherObject();
Alternatively, declare your function to return a "copy" to your object, instead of a reference like I'm assuming you are returning right now:
AnotherObject f()
{
return AnotherObject(); // return value optimization will kick in anyway!
}
The function must be declared to return a reference, and a reference has to refer to an object that will continue to exist after the function exits. Your temporary "AnotherObject()" is destructed right after the return, so that obviously won't work. If you can't change the method signature, you may need to throw an exception instead of returning an error value.
You should change the return type of your function from "AnotherObject&" to "AnotherObject" and return that object by value. Otherwise it will go just like Blindy described
You shouldn't return a reference to a temporary which is destroyed at the end of the line, nor a reference to a local which is destroyed at the end of the function.
If you want to keep the current signature, you'd have to add a static constant instance that you can return as a default.
#include <iostream>
template <class T>
class X
{
T value;
static const T default_instance;
public:
X(const T& t): value(t) {}
const T& get(bool b) const
{
return b ? value : default_instance;
}
};
template <class T>
const T X<T>::default_instance = T();
int main()
{
X<int> x(10);
std::cout << x.get(true) << ' ' << x.get(false) << '\n';
}
You may also return by value or return a pointer in which case you can return NULL.
The call to AnotherObject's constructor creates a new instance on the stack, which is immediatly destroyed when the method returns.
It is most likely not a good idea to create and return new object if the find fails. The calling code will have no way to tell if the object returned is a previously existing object present in the data structure.
If you do want to do this, then you should add the new object to the data structure and then return an iterator pointing to the new object IN THE DATA STRUCTURE.
Something like this:
if (it == this->end()) {
it = this->insert(pair<ExString, AnotherObject>( string, AnotherObject() ));
return it->second;
}
I personally think that this is a bit of a hack, but as long as you really stick to the const'ness of the returned reference you should be able to return a statically constructed instance of AnotherObject whose only "raison d'etre" is to be the "not found" return value of your function. Make it a static const private member of your class Object for example, and you should be ok as long as a default constructed instance of AnotherObject is not a valid value to be contained in an instance of Object.
Related
#include <iostream>
#include <string>
using namespace std;
class Wrapper
{
public:
std::string&& get() &&
{
std::cout << "rvalue" << std::endl;
return std::move(str);
}
const std::string& get() const &
{
std::cout << "lvalue" << std::endl;
return str;
}
private:
std::string str;
};
std::string foo()
{
Wrapper wrap;
return wrap.get();
}
std::string bar()
{
Wrapper wrap;
return std::move(wrap.get());
}
std::string fooRvalue()
{
return Wrapper().get();
}
std::string barRvalue()
{
return std::move(Wrapper().get());
}
int main() {
while(1)
{
std::string s = foo();
std::string s2 = bar();
std::string s3 = fooRvalue();
std::string s4 = barRvalue();
}
return 0;
}
Is the return value of const std::string&, and std::string&& safe in this use case (pretend std::string is some other type that may be not copyable). I thought it would not work because the refernce should point to some local variable which would go out of scope, but it appears to work just fine? Also i've seen the && syntax used before, did i use it correctly (i restricted it to when Wrapper is itself an rvalue).
Im just a little generally confused when returning a reference is safe, i thought the rule was that the object had to outlive the value being returned but i've seen things like the standard library and boost returing reference before. If i store the reference they give me in a variable (that is not a reference) it all seems to work just fine if i then return that stored variable. Can someone fix me up, and give me some good rules to follow.
Here's the ideone i was playing around with, it all seems to work: http://ideone.com/GyWQF6
Yes, this is a correct and safe way of implementing a member getter. But you could make one improvement, which I'll get to. The key is that the lifetime of the std::string member is (almost) the same as the lifetime of the Wrapper object which contains it. And a temporary is only destroyed at the end of the full-expression where it appears, not immediately after it's "used". So in return std::move(Wrapper().get());, the Wrapper is created, get() is called, std::move is called, the return value is constructed, and only then the Wrapper and its string are destroyed.
The only danger is if somebody binds another reference to your member. But that would be their mistake, and ordinary const-reference getters have the same danger. This is the equivalent of the incorrect const char* ptr = "oops"s.c_str();.
std::string foo()
{
Wrapper wrap;
return wrap.get();
}
foo copy constructs the return value from the member. Hopefully that's not a surprise.
std::string bar()
{
Wrapper wrap;
return std::move(wrap.get());
}
bar also copy constructs the return value from the member. What's going on here is that since wrap is an lvalue, the lvalue get() is called, which returns a const lvalue. (Informally, "const std::string&".) Then move converts that to an xvalue, but it's still const. (Informally, "const std::string&&".) The move constructor string(string&&) cannot match here, since the argument is const. But the copy constructor string(const string&) can match, and is called.
If you expected bar to move construct the return value, you may want to add a third overload for non-const lvalues:
std::string& get() & { return str; }
(If you didn't want to allow modifying the member, note that you already sort of did. For example, somebody could do std::move(wrap).get() = "something";.)
Also, if you had return std::move(wrap).get(); instead, that would have move constructed the return value even without the third overload.
std::string fooRvalue()
{
return Wrapper().get();
}
fooRvalue move constructs the return value, since the rvalue get() is used. As already mentioned, the Wrapper lives long enough for this construction to be safe.
std::string barRvalue()
{
return std::move(Wrapper().get());
}
In barRvalue, the move call is absolutely useless. The expression Wrapper().get() is already an xvalue, so move just converts an xvalue of type std::string to ... an xvalue of type std::string. Still just as safe, though.
The return value object of a function will be initialized before the destruction of local variables and temporaries created in the return expression. As such, it is perfectly legitimate to move from locals/temporaries into function return values.
Those four global functions work because they return objects, not references to objects. And that object gets constructed before any of the locals that their constructor parameter reference are destroyed.
barRvalue is rather redundant (since the result of Wrapper().get() is already an rvalue reference), but functional.
Im just a little generally confused when returning a reference is safe
A function returning a reference to an object that has been destroyed is what is unsafe. Returning a reference to a local object, or part of a local object, is unsafe.
Returning a reference to *this or some part of *this is safe, because the this object will outlive the function that returns the reference. It's no different from returning a reference to a parameter that you take by pointer/reference. The object will outlive the function call that returns the reference.
I'm somewhat confused about the declaration of functions returning const references to temporaries.
In the following code
#include <string>
#include <iostream>
using namespace std;
const string& foo() {
return string("foo");
}
string bar() {
return string("bar");
}
int main() {
const string& f = foo();
const string& b = bar();
cout << b;
}
What is the difference between methods foo and bar ?
Why does foo give me warning: returning reference to local temporary object [-Wreturn-stack-address]. Isn't a copy of the temporary created on const string& f = foo(); ?
string("foo") creates an object of type std::string containing the value "foo" locally in the function. This object will be destroyed at the end of the function. So returning the reference to that object will be invalid once the code leaves that function [1]. So in main, you will never have a valid reference to that string. The same would be true if you created a local variable inside foo.
The WHOLE point of returning a reference is that you don't make a copy, and initializing a reference (string &f = foo() is an initialization) will not create a copy of the original object - just another reference to the same object [which is already invalid by the time the code is back in main]. For many things, references can be seen as "a different name for the same thing".
The lifetime of the referred object (in other words, the actual object the "alias name" refers to) should ALWAYS have a lifetime longer than the reference variable (f in this case).
In the case of bar, the code will make a copy as part of the return string("bar");, since you are returning that object without taking its reference - in other words, by copying the object, so that works.
[1] pedantically, while still inside the function, but after the end of the code you have written within the function, in the bit of code the compiler introduced to deal with the destruction of objects created in the function.
Isn't a copy of the temporary created on const string& f = foo();
Where did you hear that?
Adding const to a reference often allows the lifetime of a temporary with which it's been initialised to be extended to the lifetime of the reference itself. There's never a copy.
Even that's not the case here, though. The object you're binding to the reference goes out of scope at the end of the function and that takes precedence over everything else.
You're returning a dangling reference; period.
Why does foo give me warning: returning reference to local temporary
object [-Wreturn-stack-address].
You are creating a temporary string object inside foo(), and you are returning a reference to that object which will immediately go out of scope (dangling reference).
const string& foo() {
return string("foo"); // returns constant reference to temporary object
} // object goes out of scope
bar() is quite different:
string bar() {
return string("bar"); // returns a copy of temporary string
}
...
const string& b = bar(); // reference an rvalue string
What is the difference between methods foo and bar ?
foo() returns a constant (dangling) reference while bar() returns a copy of a temporary string object.
In both of the cases, a string object is initialized and allocated on the stack.
After returning from the function, the memory segment which contains it becomes irrelevant, and its content may be overridden.
The difference between the functions:
bar function return a copy of the string instance which is created inside it.
foo function returns a reference to the string instance which is created inside it.
In other words, it returns an implicit pointer to its return value, which resides in a temporary memory segment - and that's the reason for your warning.
Lets consider the following piece of code:
template<typename T>
void f(std::unique_ptr<T>&& uptr) { /*...*/ }
In another function:
void g()
{
std::unique_ptr<ANY_TYPE> u_ptr = std::make_unique<ANY_TYPE>();
f(std::move(u_ptr));
X: u_ptr->do_sth(); // it works, I don't understand why. Details below.
}
I don't understand why u_ptr in line X is still alive.
After all I forced him to be moved (std::move).
---EDIT---
Ok, so now:
The code is still working:
class T{
public:
T(){}
void show(){
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr<T> ref){
ref->show();
}
int main()
{
std::unique_ptr<T> my;
my->show();
f(std::move(my));
my->show(); // How is it possible. Now, f takes unique_ptr by value
return 0;
}
You didn't show us that code to function f, but presumably it didn't move the pointer, even though it had permission to.
You passed the unique_ptr by reference. If function invocation actually moved it, then the function couldn't use it because it would be gone before the function had a chance to.
If you want function invocation to actually move the pointer, you need to pass the pointer by value, not be reference. That value would be a unique_ptr for it to be moved into. In that case, you should declare the function as taking a std::unique_ptr<T> instead of a std::unique_ptr<T>&&. Then you can actually invoke the move constructor when you call the function.
Update: With your latest change, the unique_ptr would no longer reference any valid object due to the move construction. You just never check that it does. Invoking a non-virtual method that doesn't access any member variables can work just the same whether the object is valid or destroyed because it doesn't need anything from the object. You also never made the unique_ptr actually point to anything.
Instead, make the unique_ptr point to something. After it's moved, try calling a virtual function or accessing a member whose value is changed by the destructor. Like this:
#include <iostream>
#include <memory>
class T{
public:
T() : valid (true) {}
~T() { valid = false; }
bool valid;
void show(){
std::cout << "HEJ! " << valid << std::endl;
}
};
void f(std::unique_ptr<T> ref){
ref->show();
}
int main()
{
std::unique_ptr<T> my (new T); // Make it point to a new object
my->show();
f(std::move(my));
my->show(); // Try to access
return 0;
}
in the line f(std::unique_ptr<T>&& uptr) uptr is not an object - it's a reference. a reference which capable to catch temporeries and mutate them.
it's like asking why doesn't the object get cloned in the next example
void func(std::string& str);
std::string str_ = "yyy";
func(str_);
str_ is passed by "regular" reference and won't get copied - this is what pass by reference means.
std::move only cast l-value to r-value-reference, which uptr in f(std::unique_ptr<T>&& uptr) can reference, it's a reference referencing an object. opposed to the common conception, std::move won't do any moving by itself, only casts the object to r-value-reference for the move constructor/assg. operator to kick in.
here, the pointer still holds valid data since it was not moved, only casted to r-value-reference.
if you want the object to move you have to declare the parameter as object, not reference : f(std::unique_ptr<T> uptr)
In your edit, you have undefiend behaviour, so everything may occure.
The reason why your call to show doesn't crash is because it doesn't use the this pointer (it doesn't try to modify or access a data member).
Try this:
class T{
public:
int v;
T(){}
void show(){
v = 0;
std::cout << "HEJ!\n";
}
};
void f(std::unique_ptr&& ref)
This is the answer when you initially had your f function taking a rvalue reference &&.
Your function takes a rvalue reference. Therefore, no new unique_ptr object is created yet, you are simply passing a reference.
Inside your f function, if you create a a local unique_ptr, with the parameter uptr, then finally uptr will be moved to create that new object.
template<typename T>
void f(std::unique_ptr<T>&& uptr)
{
//move uptr into local_unique_ptr
//note that we have to use move again
//because uptr has a name, therefore its a lvalue.
auto local_unique_ptr = std::unique_ptr<T>(std::move(uptr));
}
The important thing to always know is that std::move is simply a static_cast.
If you pass a lvalue to std::move, it returns a rvalue. If you pass a rvalue, it returns a rvalue. That's it.
Your function f may not in fact move the pointer. Merely taking an object by && does not modify the object.
u_ptr->do_sth() may invoke a static member function or a member function that does not access the object (this) and this is why it does not crash.
I've been reading Myers book and came across the item on returning by reference/pointer vs by value.
The point is, if our function for example is like this:
ClassA& AddSomething(ClassA classA)
{
ClassA tempClassA;
//... do something on tempClassA
return tempClassA;
}
This would not work because we are returning a reference to a object that was created on the stack and it is dead now that the function is done.
He gives two solutions:
Using a local static ClassA inside the function. This has its
problems but atleast we can be sure that object exists.
Return as an object:
ClassA AddSomething(ClassA classA)
{
ClassA tempClassA;
//... do something on tempClassA
return tempClassA;
}
Now if I'm to do:
ClassA obj1;
ClassA obj2 = AddSomething(obj1);
My confusion now is, when executing this line:
A 'copy' of tempClassA is made and passed to the copy constructor
of ClassA (to initialize obj2)? OR
tempClassA is passed itself to the copy constructor of ClassA,
because copy constructor takes a reference.
So basically, whats passed to the copy constructor is a reference to tempClassA (which was created in stack inside the function) or a reference to a copy of tempClassA.
Also, another question I have is, I have read that if I get a reference of a function local variable, in that case the local variable will not be deleted.
For example,
ClassA & classRef = AddSomething(obj1);
In this case, if AddSomething() is returning a reference, then classRef not be pointing to a deleted reference because the local variable will be retained. Have I understood this correctly?
At worst, you're right: a copy of tempClassA is passed to the copy constructor. But compilers are allowed to eliminate that copy and construct the result in place form tempClassA. This is known as the "Return Value Optimization", or RVO. I don't know of a compiler that doesn't do this.
When an object is returned by value, there are two copies taking place: one from the local variable into the return value, and one from the return value into the target object. However, the implementation is allowed to elide one or both of these copies; this is called return value optimisation (RVO) in the first case, and copy elision in the second.
Object some_function() {
return Object(); // copy Object() into return value; candidate for RVO
}
Object another_function() {
Object obj;
return obj; // copy obj into return value; candidate for NRVO
}
Object result = some_function(); // copy return value into result; candidate for copy elision
The second function above is a candidate for a refinement type of RVO called named return value optimisation; the simplest form of RVO applies only to return statements that construct the return value inplace.
Regarding your second question, lifetime extension only applies to const references to objects returned by value; your code in the second question will not extend the lifetime of any object. See Returning temporary object and binding to const reference for more details.
You can never return a function local variable by reference. It would NOT work even if you used const reference to capture the returned value like this:
const ClassA& classRef = AddSomething(obj1);
Because if AddSomething returns a local object by reference, it'll be a dangling reference to a non-existing object by the time classRef gets to reference it.
Have a look at the following code. The goal here is to return a reference through two functions (from ReferenceProvider::getReference() to getRef() to main()):
#include <tchar.h>
#include <assert.h>
#include <string>
class BaseClass {
public:
virtual void write() const {
printf("In base class\n");
}
};
typedef BaseClass* BaseClassPointer;
class ChildClass : public BaseClass {
public:
virtual void write() const {
printf("In child class\n");
}
};
typedef ChildClass* ChildClassPointer;
//////////////////////////////////////////////////////////////////////////
ChildClass* g_somePointer = new ChildClass();
class ReferenceProvider {
public:
const BaseClassPointer& getReference() {
const BaseClassPointer& val = g_somePointer;
return val;
}
};
ReferenceProvider g_provider;
const BaseClassPointer& getRef() {
std::string test;
const BaseClassPointer& val = g_provider.getReference();
return val;
}
int _tmain(int argc, _TCHAR* argv[]) {
BaseClass* child = getRef();
assert(child == g_somePointer);
child->write();
return 0;
}
Now, when debugging this code (in Visual C++), breaking at return val; in getRef() will give you a screen like this:
Notice how the values of g_somePointer and val are the same. Now, step over the return statement and you'll get a screen like this:
Notice how val has become invalid (0xcccccccc). This is probably because the stack of getRef() has been cleared and val is no longer available.
The problem now is that child in _tmain() will get this invalid value (0xcccccccc) rendering child unusable. So my first (and main) question is: How to do this correctly?
(Please note that this is just an boiled down example from some other code I've been working on. It needs to be structured like with, including using references to pointers.)
What's making this whole thing very strange (and hard to debug) is that the function getRef() works under some conditions:
If you change the type of g_somePointer to BaseClass* (from ChildClass*)
If you remove the local variable in getRef() (i.e. the line std::string test;)
In both cases the reference variable val (in getRef()) will not become invalid and the function will return the correct pointer address. Can anybody explain this to me?
The problem is here:
const BaseClassPointer& val = g_somePointer;
Since g_somePointer has a different type (ChildClass* is convertible to BaseClass*, but is not the same type), val cannot refer directly to g_somePointer. Instead, a temporary copy is made, converted to the correct type, and val refers to that.
The temporary only lasts as long as val, going out of scope at the end of the function, so the function returns an invalid reference.
If you change the type of g_somePointer to BaseClass* (from ChildClass*)
In that case, no pointer conversion is required, and so val can refer directly to g_somePointer. The code is then correct, but fragile.
If you remove the local variable in getRef() (i.e. the line std::string test;)
With the string variable, there is a destructor call at the end of the function, which overwrites the defunct stack frame that contains the temporary pointer. Without it, nothing overwrites the memory, so the code appears to work - which is unfortunate, as it makes the error much harder to notice.
You can never return a reference to a local object: it will always go out of scope when the function is exited. Sometimes it may appear as if it works but this is just because the data is normally not change when the stack pointer is adjusted.
To explain what's going on:
const BaseClassPointer& val = g_somePointer;
This line is the problem. Let's do away with the typedef:
BaseClass* const& val = g_somePointer;
Here, the type of g_somePointer is ChildClass*. In order to assign it to a BaseClass*, a conversion is needed. From that conversion, a temporary pointer is introduced. That pointer is bound to a reference-to-const, which extends the temporaries lifetime until the reference dies, which is exactly the case after your return val; statement. At that point, the temporary base-class pointer doesn't exist anymore and you have undefined behaviour.
To avoid all that mess, just return a BaseClass*.
You don't want to do something like that. Returning a reference to local memory is the same as returning the address of local memory, which is undefined behavior. All sorts of things can go wrong (or by chance, things can go right).
If you want the "val" to "survive", getReference() method should return a reference to a static object. Is that "static" going to work in your current architecture is another question.
You're returning a const reference to the local val instead of the returned getRef().
Also, how do you transform the pointer to a reference?
const BaseClassPointer& val = g_somePointer;
return val;
won't work if g_somePointer is a pointer - did you use *g_somePointer or similar?