如果以下代码(func1())必须返回i,是否正确?我记得在某处读过,返回对局部变量的引用时出现问题。与func2()有何不同?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
如果以下代码(func1())必须返回i,是否正确?我记得在某处读过,返回对局部变量的引用时出现问题。与func2()有何不同?
int& func1()
{
int i;
i = 1;
return i;
}
int* func2()
{
int* p;
p = new int;
*p = 1;
return p;
}
Answers:
此代码段:
int& func1()
{
int i;
i = 1;
return i;
}
将不起作用,因为您将向对象返回别名(引用),且该对象的生存期限于函数调用的范围。这意味着一旦func1()
返回便int i
死亡,使从函数返回的引用变得一文不值,因为它现在引用的对象不存在。
int main()
{
int& p = func1();
/* p is garbage */
}
第二个版本确实可以工作,因为变量是在免费存储区上分配的,这不受函数调用的生存期的约束。但是,您有责任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
它了。
无论哪种情况,您都可以返回值本身(尽管我知道您提供的示例可能是人为设计的):
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();
}
有趣的是,将临时绑定到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();
}
int* p = func2(); delete p;
现在,当删除'p'时,是否意味着分配在函数func2()
定义内的内存也被删除了?
func2()
,在下一行释放到外部。但是,这是处理内存的一种非常容易出错的方式,就像我说过的那样,您将改用RAII的某种变体。顺便说一句,您听起来好像在学习C ++。我建议选择一本很好的C ++入门书以供学习。另外,如果您有问题,以备将来参考,可以随时将问题发布到堆栈溢出中。评论不是要提出全新的问题。
局部变量是堆栈上的内存,超出范围时不会自动使该内存无效。从嵌套更深的Function(在内存中的栈中更高)开始,访问此内存是绝对安全的。
一旦函数返回并结束,事情就会变得很危险。通常,当您返回时,内存不会被删除或覆盖,这意味着地址中的内存仍包含您的数据-指针似乎有效。
直到另一个函数建立了堆栈并覆盖了它。这就是为什么它可以工作一会儿的原因-然后在一个特别深层嵌套的函数集或一个具有非常大的尺寸或许多本地对象的函数再次到达该堆栈内存后突然停止起作用。
甚至可能再次到达同一程序部分,并用新的函数变量覆盖旧的本地函数变量。所有这一切都是非常危险的,应该强烈反对。 不要使用指向本地对象的指针!
这些简单的规则值得记住,它们适用于参数和返回类型...
每个都有时间和地点,因此请确保您了解它们。正如您在此处显示的那样,局部变量仅限于它们在函数作用域中局部存在的时间。在您的示例中,返回类型为int*
and returning &i
同样是不正确的。在这种情况下,您最好这样做...
void func1(int& oValue)
{
oValue = 1;
}
这样做将直接更改您传入参数的值。而此代码...
void func1(int oValue)
{
oValue = 1;
}
不会。它将只更改oValue
函数调用的本地值。这样做的原因是因为您实际上只是在更改的“本地”副本oValue
,而没有更改oValue
本身。
int& i = * new int;