C++ Returning reference to temporary [duplicate]
Possible Duplicate:
warning: returning reference to temporary
I am getting the error "returning reference to tempo开发者_Go百科rary" 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.
精彩评论