【问题标题】:How C++ reference worksC++ 参考的工作原理
【发布时间】:2011-11-17 02:57:51
【问题描述】:

在 C++ 工作了 15 年之后,我发现我并不完全理解引用...

类测试类 { 民众: 测试类():m_nData(0) { } 测试类(int n):m_nData(n) { } ~TestClass() { cout

我从这个测试中了解到,TestClass 实例是在堆栈上创建的(这是正确的吗?)并由第一个 TestClass 构造函数初始化。什么时候分配这个实例:什么时候加载主函数,或者执行引用赋值?什么时候销毁?

第二次引用赋值后对象地址不变。这是否意味着析构函数和构造函数应用于同一个内存区域?或者内存被释放(动态?在堆栈上?)并再次分配?

我对堆栈和堆分配对象的生命周期、它们的构造函数和析构函数了如指掌。但我无法理解这个程序到底发生了什么。

编辑: 谢谢大家。我试图在这个测试中重现一些其他(更复杂的)程序行为。您的 cmets 帮助我理解了我的错误和我正在与之抗争的另一个程序......

固定代码为:

主函数() { cout

【问题讨论】:

  • 此代码无法编译。您不能将非常量引用绑定到临时对象。
  • 是否有任何不将自动对象放入堆栈的 C++ 实现?如果有,它们是哪些?
  • 你用哪个编译器来编译它?它不应该编译。
  • @Jeremy:没有,这在逻辑上是不可能的。令人费解的是,那些宣传城市神话的人都是白痴。我无法解释他们为什么这样做,除了可能就像那个因与人行道发生性关系而被判刑的苏格兰人一样,这只是莫名其妙的行为。
  • 请保持 cmets 具有建设性和主题性。

标签: c++ reference


【解决方案1】:

您的代码存在多个问题,最终没有意义。但是,让我们破解它。

1) 您只能将临时对象绑定到 const 引用,从而延长其生命周期:

const TestClass & c = TestClass();

2) 现在我们不能使用dump,因为你没有声明它const

void Dump() const

3) 说c = TestClass() 是一项任务。然而,c 现在是一个对 const 的引用,它不能被赋值,因为赋值是非常量的(原因很明显)。让我们解决这个问题:

const_cast<TestClass&>(c) = TestClass(10);

现在我们为临时但扩展的对象c 分配了一个新值,一切正常:

main started
data = 0  ptr = 0x0xbfa8219c
destructor
data = 10  ptr = 0x0xbfa8219c
main ended
destructor

指针是相同的,因为只有一个对象,即c 引用的(临时)对象。分配给它是一种黑客行为,通常是未定义的行为,但出于本演示的目的,我们侥幸逃脱。

中间析构函数是第二个临时TestClass(10)的析构函数。

【讨论】:

    【解决方案2】:
    TestClass& c = TestClass(); // TestClass() temporary doesn't persist beyond this expression.
    c.Dump();
    

    TestClass() 会创建一个临时对象,您不能对其进行引用。

    const TestClass& c = TestClass();
    

    const 限定将被创建的临时对象的生命周期延长到对象c 的范围。

    【讨论】:

      【解决方案3】:
      TestClass& c = TestClass();
      

      这甚至无法编译!

      尝试将临时引用绑定到非常量引用会导致编译错误。

      但是,您可以将临时绑定到 const 引用:

      {
         const TestClass& c = TestClass();
         //use c 
         //....
      }//<-------- the temporary will be destroyed here.
      

      在这种情况下,临时变量的生命周期延长到引用的生命周期,即当引用变量超出范围时,临时变量将被销毁,如上所示。

      【讨论】:

      • 这在 VC++ 2010 中编译,带有警告 C4239(级别 4)。
      • @Alex:warning 明确表示:使用了非标准扩展:“token”:从“type”转换为“type”。 ....你看到粗体字了吗?
      • 一些警告应该被视为错误...... MCVC 非常宽容。
      【解决方案4】:

      1) 你不能得到对临时对象的非 const 引用

      2) 在行 c = TestClass(10); operator=(...) 被调用

      【讨论】:

        【解决方案5】:

        一个好方法是比较指针的引用...(引用通常在汇编中以相同的方式实现,通常使用 ebx 寄存器)。主要区别在于初始化后引用是常量...

        但是,const TestClass&amp; c = TestClass(); 行与const TestClass* const pc = &amp;TestClass(); 平行,因此对象将在堆栈​​上创建和销毁,pc 仍将保持相同的地址。

        【讨论】:

          猜你喜欢
          • 2013-02-17
          • 2020-12-02
          • 1970-01-01
          • 2021-03-09
          • 2014-07-14
          • 2011-04-18
          • 2012-09-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多