如果必须返回i,下面的代码(func1())是否正确? 我记得在某处读到,当返回对一个局部变量的引用时有一个问题。 它与func2()有何不同?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
此代码段:
int& func1()
{
int i;
i = 1;
return i;
}
将无法工作,因为您返回的别名(引用)对象的生存期仅限于函数调用的范围。 这意味着一旦func1()
返回,int i
就会终止,从而使从函数返回的引用变得毫无价值,因为它现在引用了一个不存在的对象。
int main()
{
int& p = func1();
/* p is garbage */
}
第二个版本确实起作用,因为变量是在空闲存储上分配的,而空闲存储没有绑定到函数调用的生存期。 但是,您要负责delete
对分配的int
执行delete
操作。
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
int main()
{
int* p = func2();
/* pointee still exists */
delete p; // get rid of it
}
通常,您会将指针包装在某个RAII类和/或工厂函数中,这样您就不必自己delete
它了。
在这两种情况下,您都可以只返回值本身(尽管我意识到您提供的示例可能是人为的):
int func3()
{
return 1;
}
int main()
{
int v = func3();
// do whatever you want with the returned value
}
请注意,像func3()
返回原始值一样返回大对象是非常好的,因为现在几乎每个编译器都实现了某种形式的返回值优化:
class big_object
{
public:
big_object(/* constructor arguments */);
~big_object();
big_object(const big_object& rhs);
big_object& operator=(const big_object& rhs);
/* public methods */
private:
/* data members */
};
big_object func4()
{
return big_object(/* constructor arguments */);
}
int main()
{
// no copy is actually made, if your compiler supports RVO
big_object o = func4();
}
有趣的是,将临时引用绑定到常量引用是完全合法的C++。
int main()
{
// This works! The returned temporary will last as long as the reference exists
const big_object& o = func4();
// This does *not* work! It's not legal C++ because reference is not const.
// big_object& o = func4();
}
局部变量是堆栈上的内存,当您超出作用域时,该内存不会自动失效。 从嵌套较深的函数(内存中堆栈的较高位置)访问该内存是非常安全的。
一旦函数返回并结束,事情就变得危险了。 通常,当您返回时,内存不会被删除或覆盖,这意味着adresss处的内存仍然包含您的数据-指针似乎有效。
直到另一个函数建立堆栈并覆盖它。 这就是为什么这可以工作一段时间-然后突然停止工作后,一个特别深的嵌套函数集,或一个真正大的大小或许多本地对象的函数,再次到达堆栈内存。
甚至可能发生这样的情况:您再次到达相同的程序部分,并用新的函数变量覆盖旧的局部函数变量。 这一切都是非常危险的,应该大力劝阻。 不要使用指向本地对象的指针!
要记住的一件好事是这些简单的规则,它们既适用于参数,也适用于返回类型。。。
每个人都有一个时间和地点,所以一定要了解他们。 正如您在这里所展示的,局部变量仅限于它们在函数作用域中处于局部活动状态的时间。 在您的示例中,返回类型为int*
并返回&i
也同样不正确。 如果你这样做会更好。。。
void func1(int& oValue)
{
oValue = 1;
}
这样做将直接更改传入参数的值。 但是这个代码。。。
void func1(int oValue)
{
oValue = 1;
}
不会。 它只会将Ovalue
的值更改为函数调用的本地值。 这是因为您实际上只更改了Ovalue
的“本地”副本,而不是Ovalue
本身。