3 ms·
> [...] it is the only way to call the no-arguments constructor for a variable on the stack The syntax: T var{}; always value-initializes a stack allocated
by gpderetta 3y ago
> [...] it is the only way to call the no-arguments constructor for a variable on the stack
The syntax:
T var{};
always value-initializes a stack allocated variable (or a member variable or a global).
- tsimionescu 3y agoI didn't know about the empty initializer list syntax. Still, reading about it, there are cases where `T var{} ;` will do something different from `T var;`: if T is an aggregate object type, then it will invoke aggregate initialization instead of calling the no-args constructor.
- gpderetta 3y agoIf T is an aggregate, there is, by definition, no constructor (no-argument or otherwise) to call. The aggregate initialization will then recursively value initialize each member, which is what you want. The only catch is, as usual, list-initialiation. You have to hope that T is sane and any list initialization constructor with an empty list is equivalent to the nullary constructor.
- tsimionescu 3y agoThere was one case I found on SO and later reproduced, where a class B derives publically from another class A which has a protected no-args constructor. In that case, B b; is valid, but B b{}; is not, since it tries to construct an instance of A from the calling code itself using the protected constructor, which it's obviously not allowed to access. Overall I think it's safe to say that the two syntaxes have different semantics, even if they overlap in most cases.
- gpderetta 3y agoI have to try that. There are defect reports for corner cases. In any case this is also allowed: T val = T(); And copy elision is now guaranteed.
- tsimionescu 3y agoThe example looks like this: class A { protected: A() {} } class B : public A {} B x; //ok B y{}; //not ok, can't access A::A() Would the T val = T(); example work if you don't have a copy constructor at all, or no move constructor, or custom ones which do weird things? Edit: I checked, and you're right - the syntax seems to be fully equivalent in C++17 or later. Great to hear!
- gpderetta 3y agoPlayed it a little bit: this seems to be a regression and breaking change from C++14 where B would not be an aggregates, so B{} would just invoke the default constructor. This is probably an oversight, I wonder if there is a Defect Report. edit: it works by making the inheritance protected, as B is no longer an aggregate. The right fix would be to also disqualify B from aggregate status if the base class constructor is unreachable. Also making both A and B non-empty removes aggregate status, so it is really a dark corner of the language.