[英]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.