问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/50788861/list-using-with-references-changes-behavior-when-used-as-a-member