【问题标题】:Returning a reference in C++ [duplicate]在 C++ 中返回引用 [重复]
【发布时间】:2011-02-06 10:37:38
【问题描述】:

考虑以下我返回double&string& 的代码。它在双精度的情况下工作正常,但在字符串的情况下却不行。为什么行为不同?

两种情况中,当我返回一个引用时,编译器甚至不会抛出Warning: returning address of local variable or temporary

#include <iostream>
#include <string>
using namespace std;


double &getDouble(){
    double h = 46.5;
    double &refD = h;
    return refD;
}

string &getString(){
    string str = "Devil Jin";
    string &refStr = str;
    return refStr;
}

int main(){
    double d = getDouble();
    cout << "Double = " << d << endl;

    string str = getString();
    cout << "String = " << str.c_str() << endl;

    return 0;
}

输出:

$ ./a.exe
Double = 46.5
String =

【问题讨论】:

标签: c++ reference


【解决方案1】:

无论编译器做什么或不做什么,都不应该返回对局部变量的引用。编译器很容易被愚弄。您不应将代码的正确性建立在某些可能未触发的警告之上。

它没有在这里触发的原因可能是您并没有真正返回对局部变量的引用,而是返回一个对局部变量的引用的变量。编译器可能没有检测到这种更复杂的情况。它只检测以下内容:

string &getString(){
    string str = "Devil Jin";
    return str;
}

double 的情况更简单,因为它不涉及构造和销毁复杂对象,因此在这种情况下,编译器的流控制分析可能在检测错误方面做得更好。

【讨论】:

  • 函数的本地化,你的意思很明显。您可以返回对您范围之外的任何内容的引用:成员数据、作为引用的函数参数等。
  • 实际上,我认为他说即使在双重情况下也不会触发警告。所以编译器在这两种情况下都被愚弄了。它与 double 一起工作的原因可能是因为 h 在堆栈上的位置没有被覆盖。试试这个:在 main store d in a double& 然后调用其他几个函数,然后打印 d。我敢打赌它不会正确。但是,在所有情况下,您所做的都是“未定义的行为”。那里有一个很好的教训:仅仅因为它给出了正确的答案并不意味着它以正确的方式完成。 ;)
【解决方案2】:

double 的引用指的是物理上仍在内存中但不再在堆栈上的位置。你只是逃脱了它,因为内存还没有被覆盖。 double 是一个原语,string 是一个对象,并且有一个析构函数,当它超出范围时,它可能会将内部字符串清除为零长度。拨打c_str() 并没有收到垃圾,这一事实似乎支持了这一点。

【讨论】:

  • 老实说,这一切似乎都是猜测,实际上并不重要。当您返回对局部变量的引用时,编译器可以做它想做的任何事情。如果感觉像休息一下然后去厨房给自己做一个三明治,那么按照标准也很好。所以答案很简单:除非变量不是函数的本地变量,否则不要返回引用。
  • 这就是为什么我说“逍遥法外”。我不支持只是试图回答“为什么?”的行为
  • @wilhelmtell:这不是猜测,而是会发生什么。问题是一旦你使用了返回值,就会发生各种各样的坏事:最好的事情是你的程序段错误;最糟糕的是,您的程序会继续运行,直到后来出现神秘的行为异常或段错误。
  • 是的,是的,我不是在批评您的回答,只是在上面添加。也许我的第一句话听起来像我做的那样。 :s
【解决方案3】:

GCC 曾经有一个名为Named Returns 的扩展,它可以让你完成同样的事情,但在函数之外分配了空间。不幸的是,它不再存在了。我不知道他们为什么把它拿出来

【讨论】:

  • +1 用于历史参考,即使它不再有效。欢迎来到 SO。
【解决方案4】:

关于 C++ 的悬空引用的经典案例。双变量不在调用堆栈上,而返回引用正试图访问它,调用编译器来设置保护标志。然而,String 具有显式的垃圾收集机制,可以让您的编译器忽略该场景。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-16
    • 1970-01-01
    • 1970-01-01
    • 2017-08-12
    • 1970-01-01
    • 2017-12-03
    • 2017-10-01
    • 1970-01-01
    相关资源
    最近更新 更多