我注意到当我意外忘记从应该返回引用的函数返回时,我没有得到任何编译器错误。我写了一些小测试来看看实际发生了什么,我比任何事情都更加困惑。
struct Foo
{
int x;
Foo() {
x = 3;
}
};
Foo* foo = new Foo;
Foo& test(bool flag) {
if (flag)
return *foo;
}
如果 test()没有(显式地)返回值,我仍然会返回一些内容。但是,返回的 Foo 对象未使用默认构造函数进行初始化 - 这是因为 x 与非显式返回值中的3不同。
当您不返回引用时实际发生了什么?如果这是一个特性,那么在发生错误时使用它作为返回虚拟对象的方法是安全的,而不是返回空指针。 (见下面的例子。)
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.
答案 0 :(得分:3)
大多数编译器会向您发出警告,但您可能需要提高编译器的警告级别才能看到它。
不,这不安全。这是坏的。它可能会导致堆栈损坏,只需返回当时堆栈上发生的任何事情。正如您已经看到的那样,不为您使用构造函数。如果你想要一个默认的构造对象,你必须自己做(但要注意返回对临时对象的引用。这也很糟糕)。
答案 1 :(得分:2)
降低编译器中引用的常用方法是指针。对于引用返回函数,它意味着您将获得表示的任意地址,无论用于返回值的寄存器或堆栈槽中是什么。
在语言中,效果未定义。
答案 2 :(得分:2)
这是未定义的行为,可能会发生无限的坏事,或者实际上可能不会发生,或者有时可能发生,或者可能同时发生,如果它不喜欢你,或者将工程师从Microsoft派到你家用棒球棒击败你的头部。
答案 3 :(得分:1)
所描述的行为不仅限于返回引用的函数。以下代码也将编译:
int func1( int i )
{
if( i )
return 3; // C4715 warning, nothing returned if i == 0
}
我不确定他们为什么只生成一个warning,而不是一个错误(设置中可能有一个选项可以将其变为错误),但是如果调用这样的函数,你将得到未定义的行为
答案 4 :(得分:1)
引用通常只是指针的语法糖,因此返回将从堆栈中获取返回值的指针值。如果你不给它它只会抓垃圾。
我必须使用该函数,然后添加-Wall以使g ++抱怨:
g ++ -Wall foo.cc foo.cc:在成员函数'Foo& FooFactory :: createFooRef()': foo.cc:19:警告:控件到达非空函数的结尾
答案 5 :(得分:0)
您是否尝试使用/ O1优化或更高版本进行编译并将警告视为错误?那可能会失败。我记得在GCC 4.1中发生的那些事情。您可能忘记在调试模式下返回引用,但引用将返回;只要你对它进行任何优化,它仍然会编译,但不会返回引用。在文本编辑器中进行编码时(就像我那时那样),这对我来说是一种彻底的痛苦和巨大的惊喜。