提问者:小点点

C++返回对局部变量的引用


如果必须返回i,下面的代码(func1())是否正确? 我记得在某处读到,当返回对一个局部变量的引用时有一个问题。 它与func2()有何不同?

int& func1()
{
    int i;
    i = 1;
    return i;
}

int* func2()
{
    int* p;
    p = new int;
    *p = 1;
    return p;
}

共3个答案

匿名用户

此代码段:

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处的内存仍然包含您的数据-指针似乎有效。

直到另一个函数建立堆栈并覆盖它。 这就是为什么这可以工作一段时间-然后突然停止工作后,一个特别深的嵌套函数集,或一个真正大的大小或许多本地对象的函数,再次到达堆栈内存。

甚至可能发生这样的情况:您再次到达相同的程序部分,并用新的函数变量覆盖旧的局部函数变量。 这一切都是非常危险的,应该大力劝阻。 不要使用指向本地对象的指针!

匿名用户

要记住的一件好事是这些简单的规则,它们既适用于参数,也适用于返回类型。。。

  • value-创建相关项的副本。
  • 指针-引用相关项目的地址。
  • reference-字面上是有问题的项目。

每个人都有一个时间和地点,所以一定要了解他们。 正如您在这里所展示的,局部变量仅限于它们在函数作用域中处于局部活动状态的时间。 在您的示例中,返回类型为int*并返回&i也同样不正确。 如果你这样做会更好。。。

void func1(int& oValue)
{
    oValue = 1;
}

这样做将直接更改传入参数的值。 但是这个代码。。。

void func1(int oValue)
{
    oValue = 1;
}

不会。 它只会将Ovalue的值更改为函数调用的本地值。 这是因为您实际上只更改了Ovalue的“本地”副本,而不是Ovalue本身。

相关问题


MySQL Query : SELECT * FROM v9_ask_question WHERE 1=1 AND question regexp '(c++|返回|局部变量|引用)' ORDER BY qid DESC LIMIT 20
MySQL Error : Got error 'repetition-operator operand invalid' from regexp
MySQL Errno : 1139
Message : Got error 'repetition-operator operand invalid' from regexp
Need Help?