C++: References as return values
I noticed I don't get any compiler errors when I accidentally forget to ret开发者_开发技巧urn from a function that is supposed to return a reference. I wrote some small tests to see what actually happens and I got more confused than anything.
struct Foo
{
int x;
Foo() {
x = 3;
}
};
Foo* foo = new Foo;
Foo& test(bool flag) {
if (flag)
return *foo;
}
If test() doesn't (explicitly) return a value, I will still get something returned. However the Foo object that is returned is not initialized using the default constructor — that's because x is different from 3 in the non-explicitly returned value.
What is actually happening when you don't return a reference? If this is a feature, is it safe to use it as a means to return dummy objects in case errors occur, as opposed to returning a null pointer. (See example below.)
class FooFactory
{
// Return reference...
Foo& createFooRef() {
Foo* foo = new Foo;
bool success = foo->load();
if (success)
return *foo;
// Implicit (and safe?) return value on failure?
}
// ... as opposed to returning a pointer.
Foo* createFooPtr() {
Foo* foo = new foo;
bool success = foo->load();
if (success)
return foo;
else
return 0;
}
// Yes, I am aware of the memory leaks,
// but that's not the point of the example.
Most compilers will give you a warning about this, but you may have to crank up the warning level of the compiler to see it.
No, this is not safe. It is bad. It may lead to stack corruption by just returning whatever happens to be on the stack at the time. As you've already seen, it does not use a constructor for you. If you want a default constructed object, you have to do that yourself (but be careful about returning a reference to a temporary object. That's also bad).
The usual way to lower references in compilers is to pointers. For a reference-returning function, it will mean you get an arbitrary address represented, whatever was in the register or stack slot used for the return value.
Formally in the language, the effects are undefined.
This is undefined behaviour, and infinite bad things may happen, or indeed, may not happen, or might happen sometimes, or might simultaneously happen and not happen if it doesn't like you, or send engineers from Microsoft to your house to beat you over the head with a baseball bat.
The described behaviour is not limited to functions that returns references. The following code will also compile:
int func1( int i )
{
if( i )
return 3; // C4715 warning, nothing returned if i == 0
}
I'm not sure why they generate just a warning, not an error (there might be an option in settings to turn it into error), but you will get undefined behaviour if you call such a function
References are typically just syntactic sugar for pointers, so the return is going to grab a pointer's worth of bytes from the stack for the return value. If you aren't giving it that it will just grab garbage.
I had to use the function and then add -Wall to get g++ to complain:
g++ -Wall foo.cc foo.cc: In member function 'Foo& FooFactory::createFooRef()': foo.cc:19: warning: control reaches end of non-void function
Have you tried compiling with /O1 optimisations or greater on and treat warnings as errors? That might fail. I remember something along those lines happening in GCC 4.1. You could forget to return the reference in debug mode, but the reference would return; as soon as you put any optimisations on it would still compile, but not return the reference. When coding in a text editor (as I was in those days) it was a total pain and a huge surprise to me.
精彩评论