1

Experimenting with this question/answer https://stackoverflow.com/a/50649120/225186 I produced what seems to be a legal recursive self referential class that implements a circular list:

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);
}

However, when I try put this as a member of a larger class I get a warning from the compiler and the behavior changes.

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
}

The warning I get is gcc: warning: a temporary bound to ‘A::n’ only persists until the constructor exits [-Wextra]. I don't believe that the warning is correct, however it is consistent with the later runtime error.

I admit that the class is non-conventional, however, how can it be that a class that it changes behavior inside a class?

Am I missing something?

alfC
  • 14,261
  • 4
  • 67
  • 118

1 Answers1

2

Aggregate initialization allows binding references to temporaries (and this causes lifetime extension). Your first example is aggregate initialization because node is an aggregate.

However, in a constructor member initializer list, it is ill-formed to bind a reference to a temporary (C++17 class.base.init/11). This is because there is no lifetime extension in that situation , and allowing it would inevitably produce a dangling reference. In the second example node is not an aggregate because it has a user-provided constructor.

M.M
  • 138,810
  • 21
  • 208
  • 365
  • Thank you, very clear. You are right, if I remove the constructor and do aggregate initialization `A a{ {3, {4, a.n}}, 99 };` then it works. However, I can't remove the custom constructor for `A`, do you see any workaround? – alfC Jun 10 '18 at 23:55
  • @alfC not really; this idea is probably more of a curiosity than a thing of practical use – M.M Jun 10 '18 at 23:59
  • Actually, I have an use for it, I need a unmutable list that can be constructed in the stack (without managing heap memory). – alfC Jun 11 '18 at 00:05