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

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 不是聚合,因为它具有用户提供的构造函数。