【问题标题】:Using a reference member out of scope使用超出范围的引用成员
【发布时间】:2018-07-21 03:53:46
【问题描述】:

这个问题涉及函数堆栈和引用成员(我读到的通常被认为是不好的做法)。我的测试代码:

#include <iostream>
using namespace std;

struct Person 
{
    Person(const int& s) : score(s) {}
    const int& score;
};

int main()
{
    Person p(123);
    cout << "P's score  is: " << p.score << endl;
    return 0;
}

我们在 Person 的构造函数中创建一个整数对象。由于将 int 转换为 &int(这就是我们需要 const 的原因),因此创建了一个模板对象。然后我们将得分点设置为构造函数的参数。最后,我们退出构造函数,参数被销毁。

输出:

P's score is: 123

如果参数被破坏,为什么我们仍然得到值 123?如果我们将参数复制给成员,这对我来说是有意义的。我的逻辑告诉我该成员会指向一个显然不正确的空位置。也许这个论点并没有真正被破坏,而是超出了范围?

当我读到这个问题时出现了这个问题:Does a const reference prolong the life of a temporary?

我发现 Squirrelsama 的答案很清楚,并且在尝试此代码之前我以为我理解了它。

2018 年 2 月 12 日更新: 有关此的更多信息: What happens when C++ reference leaves it's scope?

2018 年 2 月 18 日更新: 这个问题是在不清楚 C++ 中引用、指针和动态内存如何工作的情况下提出的。任何为此苦苦挣扎的人,我建议阅读这些内容。

【问题讨论】:

  • 当你使用引用时,它引用了原始存储地址。 score 因此包含幻数 123 的地址,它在您的应用程序运行时不会“销毁”。
  • 这是有道理的。有没有人愿意建议我为什么这个问题被认为是不好的(反对票),以便我将来可以写出更好的问题?我相信没有违反 Stackoverflow 规则。
  • 别担心。人们应该在这里投票的标准是他们是否认为帖子“有用”。正如您可能猜到的那样,这取决于解释和投票者的恶劣情绪。所以,从容应对吧。
  • s 的生命周期不会通过函数范围而延长。 const int&amp; score; 不是函数本地的。它是一个数据成员。这是 UB。
  • 你有未定义的行为ideone.com/4FXakx

标签: c++ constructor scope reference


【解决方案1】:

如果参数被破坏,为什么我们仍然得到值 123?

因为没有什么能保证你不会。在 C++ 中,访问一个生命周期已经结束的对象(当你访问它时你的临时对象已经死了)会导致未定义的行为。未定义的行为并不意味着“崩溃”或“得到空结果”。这意味着语言规范没有规定结果。您无法从纯 C++ 的角度推断程序的结果。

现在可能发生的事情是,您的 C++ 实现会为该临时文件保留存储空间。即使它可能p 初始化后重用该位置,但这并不意味着它必须这样做。因此,您最终只能靠运气阅读“正确的价值”。

【讨论】:

  • 这是正确的结论吗:构造函数参数有自动存储期限(一旦构造函数返回,它将超出范围)?引用成员设置为模板对象的地址,并保持为 Person 的成员。模板对象本身保存在动态内存中,其命运未定义(可能被覆盖)。
  • @Trollblender - 除了最后一个。临时对象就是这样,临时的。它的创建位置未指定在哪里,只是它会过期。它可以很好地分配为本地自动对象。
【解决方案2】:

通过在您的对象中存储引用,您拥有的唯一保证是您跟踪该对象,只要该对象是有效的。当对象不再有效时,您可以访问不再有效的东西。

在您的示例中,您在某处分配了一个临时对象 (123),并通过引用机制跟踪该对象。当您使用此引用时,您无法保证您正在跟踪的对象仍然有效。

【讨论】:

  • 所有关于内存地址的讨论都涉及编译器实现级别,而不是 C++ 语言级别。特别是,"you keep the address of where it has been assigned" 是错误的,因为 OP 从不获取引用的 int 对象的地址;代码中的任何地方都没有&amp; 运算符。
  • const int& 分数
  • 这不是&amp; 运算符。
  • 更准确地说:引用声明中的&amp; 字符与地址运算符无关,它也使用&amp; 字符。注意还有std::addressof
  • 如果我错了,请纠正我,但谈话的重点是跟踪丢失的对象,对吗?如果是这种情况,我将用跟踪对象替换单词地址。我想指出的是,您使用引用跟踪对象,而不是持有该对象。是不是更清楚了?
猜你喜欢
  • 2010-11-22
  • 2018-12-10
  • 2019-06-09
  • 2017-11-15
  • 1970-01-01
  • 2018-03-30
  • 1970-01-01
  • 1970-01-01
  • 2018-12-30
相关资源
最近更新 更多