简单的例子:
struct A
{
A() : i(int()) {}
const int& i;
};
来自 gcc 的错误:
临时绑定到 'A::i' 只会持续到构造函数退出
来自 12.2p5 的规则:
临时绑定到构造函数的 ctor-initializer (12.6.2) 中的引用成员将持续存在,直到构造函数退出。
问题
有人知道这条规则的基本原理吗?在我看来,让临时人活到参考死亡会更好。
简单的例子:
struct A
{
A() : i(int()) {}
const int& i;
};
来自 gcc 的错误:
临时绑定到 'A::i' 只会持续到构造函数退出
来自 12.2p5 的规则:
临时绑定到构造函数的 ctor-initializer (12.6.2) 中的引用成员将持续存在,直到构造函数退出。
问题
有人知道这条规则的基本原理吗?在我看来,让临时人活到参考死亡会更好。
我不认为不扩展到对象生命周期需要证明。相反会!
临时对象的生命周期扩展仅扩展到封闭范围,这既自然又有用。这是因为我们严格控制接收引用变量的生命周期。相比之下,类成员根本不是真正的“范围内”。想象一下:
int foo();
struct Bar
{
Bar(int const &, int const &, int const &) : /* bind */ { }
int & a, & b, & c;
};
Bar * p = new Bar(foo(), foo(), foo());
foo()
为临时人员定义有意义的寿命延长几乎是不可能的。
相反,我们有默认行为,即foo()
临时的生命周期延伸到包含它的完整表达式的末尾,并且没有更多。
它会生活在什么样的记忆中?
为了让它按照您建议的方式工作,它不能在堆栈上,因为它必须比任何单个函数调用的寿命更长。它不能放在内存中的 struct A 之后,因为它无法知道 A 是如何分配的。
充其量,它必须变成一个秘密的堆分配。这将需要在析构函数运行时进行相应的秘密释放。复制构造函数和赋值运算符也需要秘密行为。
我不知道是否有人真正考虑过这样做。但就个人而言,对于一个相当晦涩的功能来说,这听起来过于复杂。
构造函数初始化列表中的 int() 在堆栈上。
一旦设置了该值, int() 就会超出范围并且引用变得无效。