繁体   English   中英

C++ 参考的工作原理

[英]How C++ reference works

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

class TestClass
{
public:
    TestClass() : m_nData(0)
    {
    }

    TestClass(int n) : m_nData(n)
    {
    }

    ~TestClass()
    {
        cout << "destructor" << endl;
    }

    void Dump()
    {
        cout << "data = " << m_nData << "  ptr = 0x" << hex << this << dec << endl;
    }

private:
    int m_nData;
};

int main()
{
    cout << "main started" << endl;

    TestClass& c = TestClass();
    c.Dump();

    c = TestClass(10);
    c.Dump();

    cout << "main ended" << endl;

    return 0;
}

// prints:
// main started
// data = 0  ptr = 0x0012FF54
// destructor
// data = 10  ptr = 0x0012FF54
// main ended
// destructor

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

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

我知道关于堆栈和堆分配对象的生命周期、它们的构造函数和析构函数的一切,但我无法理解这个程序中究竟发生了什么。

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

固定代码是:

int main()
{
    cout << "main started" << endl;
    TestClass t;

    TestClass& c(t);
    c.Dump();

    c = TestClass(10);
    c.Dump();

    cout << "main ended" << endl;
    return 0;
}

29.06.2022 的注意事项:在 Daniel Walker 的最新版本之后,这个问题看起来完全是废话。 我对此不负责任。

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

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引用的(临时)对象。 分配给它是一种通常是未定义行为的 hack,但出于本演示的目的,我们侥幸逃脱。

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

TestClass& c = TestClass(); // TestClass() temporary doesn't persist beyond this expression.
c.Dump();

TestClass()创建一个临时的,你不能引用它。

const TestClass& c = TestClass();

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

TestClass& c = TestClass();

这甚至不会编译!

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

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

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

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM