C ++返回引用局部variables
如果它必须返回i,下面的代码(func1())是否正确? 我记得在某个地方读到返回引用局部variables时有问题的地方。 与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 */ }
第二个版本可以工作,因为这个variables是在free store上分配的,而不是绑定到函数调用的生命周期。 但是,您有责任delete
分配的int
。
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
它。
无论哪种情况,你都可以直接返回值(尽pipe我知道你提供的例子可能是人为的):
int func3() { return 1; } int main() { int v = func3(); // do whatever you want with the returned value }
请注意,以相同的方式返回大对象是很好的, func3()
返回原始值,因为现在每个编译器都实现了某种forms的返回值优化 :
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(); }
有趣的是,绑定一个临时的const引用是完全合法的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(); }
局部variables是堆栈中的内存,当超出作用域时,内存不会自动失效。 从一个函数更深的嵌套(在内存中更高的堆栈),它是完全安全的访问这个内存。
一旦函数返回并结束,事情就会变得危险。 通常情况下,内存不会在您返回时被删除或覆盖,这意味着该地址的内存仍然包含您的数据 – 指针似乎是有效的。
直到另一个函数build立堆栈并覆盖它。 这就是为什么它可以工作一段时间 – 然后突然停止function后,一个特别深的嵌套function,或一个真正巨大的或许多本地对象的函数,再次达到该堆栈内存。
甚至可能发生,你再次到达相同的程序部分,并用新的函数variables覆盖旧的本地函数variables。 所有这一切都是非常危险的,应该非常沮丧。 不要使用指向本地对象的指针!
这些简单的规则是值得记住的,它们适用于参数和返回types。
- 价值 – 制作相关项目的副本。
- 指针 – 指相关项目的地址。
- 参考 – 是字面上的问题。
每个人都有时间和地点,所以一定要认识他们。 正如你在这里所显示的,局部variables就是这样的,仅限于它们在函数范围内本地存在的时间。 在你的例子有一个返回types的int*
和返回&i
也一样不正确。 在这种情况下,你会更好…
void func1(int& oValue) { oValue = 1; }
这样做会直接改变传入参数的值。 而这个代码…
void func1(int oValue) { oValue = 1; }
不会。 它只会将oValue
本地的值更改为函数调用。 原因是因为你实际上只是改变了oValue
的“本地”副本,而不是oValue
本身。