与引用一起使用的列表,在用作成员时更改行为

List using with references, changes behavior when used as a member

本文关键字:成员 一起 引用 列表      更新时间:2023-10-16

在试验这个问题/答案 https://stackoverflow.com/a/50649120/225186,我产生了一个似乎是实现循环列表的法律递归自引用类:

struct node{
int val;
node const& next;
};
int main(){
node s{3, {4, s}};
assert(s.val == 3);
assert(s.next.val == 4);
assert(&s.next.next == &s);
assert(s.next.next.val == 3);
}

但是,当我尝试将其作为较大类的成员时,我会收到编译器的警告,并且行为发生了变化。

struct A{
node n;
int i;
A(int a, int b) : n{a, {b, n}}{} // warning here, also tried n{a, node{b, n}}
};
int main(){
A a(3, 4);
assert( a.n.val == 3 );
assert(&(a.n.next.next) == &(a.n)); // this assert fail and 
assert( a.n.next.val == 4 ); // segmentation fault here
}

我得到的警告是gcc: warning: a temporary bound to ‘A::n’ only persists until the constructor exits [-Wextra]. 我不相信警告是正确的,但它与后来的运行时错误一致。

我承认这个类是非传统的,但是,它怎么可能改变类内部的行为呢?

我错过了什么吗?

聚合初始化允许绑定对临时的引用(这会导致生存期延长(。 您的第一个示例是聚合初始化,因为node是一个聚合。

但是,在构造函数成员初始值设定项列表中,将引用绑定到临时 (C++17 class.base.init/11( 的格式不正确。这是因为在那种情况下没有寿命延长,允许它不可避免地会产生一个悬而未决的参考。 在第二个示例中,node不是聚合,因为它具有用户提供的构造函数。