代码之家  ›  专栏  ›  技术社区  ›  alfC

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

  •  1
  • alfC  · 技术社区  · 6 年前

    尝试这个问题/答案 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] . 我不相信警告是正确的,但是它与后面的运行时错误是一致的。

    不过,我承认这门课不是传统的, 它如何能够改变类内的行为?

    我错过什么了吗?

    1 回复  |  直到 6 年前
        1
  •  2
  •   M.M    6 年前

    聚合初始化允许绑定对临时文件的引用( and this causes lifetime extension )。你的第一个例子是 aggregate initialization 因为 node 是一个集合。

    但是,在构造函数成员初始化器列表中,将引用绑定到临时(C++ 17类.Base.init/11)是不正确的。这是因为在这种情况下没有寿命延长,并且允许它不可避免地会产生悬空的引用。在第二个例子中 节点 不是聚合,因为它具有用户提供的构造函数。