列表与引用一起使用,作为成员使用时会更改行为
List using with references, changes behavior when used as a member
对此进行试验 question/answer 我生成了一个似乎合法的递归自引用 class 实现循环列表:
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);
}
但是,当我尝试将其作为更大 class 的成员时,我收到了编译器的警告并且行为发生了变化。
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]
。
我不认为警告是正确的,但它与后来的运行时错误一致。
我承认 class 是非常规的,但是,class 怎么会改变 class 内部的行为呢?
我是不是漏掉了什么?
聚合初始化允许绑定对临时对象的引用(). Your first example is aggregate initialization 因为 node
是一个聚合。
但是,在构造函数成员初始化列表中,将引用绑定到临时对象 (C++17 class.base.init/11) 的格式不正确。这是因为在那种情况下没有生命周期延长,并且允许它不可避免地产生悬空引用。在第二个示例中,node
不是聚合,因为它具有用户提供的构造函数。
对此进行试验 question/answer 我生成了一个似乎合法的递归自引用 class 实现循环列表:
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);
}
但是,当我尝试将其作为更大 class 的成员时,我收到了编译器的警告并且行为发生了变化。
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]
。
我不认为警告是正确的,但它与后来的运行时错误一致。
我承认 class 是非常规的,但是,class 怎么会改变 class 内部的行为呢?
我是不是漏掉了什么?
聚合初始化允许绑定对临时对象的引用(node
是一个聚合。
但是,在构造函数成员初始化列表中,将引用绑定到临时对象 (C++17 class.base.init/11) 的格式不正确。这是因为在那种情况下没有生命周期延长,并且允许它不可避免地产生悬空引用。在第二个示例中,node
不是聚合,因为它具有用户提供的构造函数。