. or even allowed by the C++11 standard?
And if so, is there any compiler that actually does it?
Here is an example of what I mean:
template&
Does the standard allow for the elision of the assignment operator? Not in the same way as for construction. If you have any construct d = ...
, the assignment operator will be called. If ...
results in an expression of the same type as d
, then the appropriate copy or move assignment operator will be called.
It is theoretically possible that a trivial copy/move assignment operator could be elided. But implementations are not allowed to elide anything that you could detect being elided.
Note that this is different from actual copy/move elision, because there the standard explicitly allows the elision of any constructor, whether trivial or not. You can return a std::vector
by value into a new variable, and the copy will be elided if the compiler supports it. Even though it is very easy to detect the elision. The standard gives special permission to compilers to do this.
No such permission is granted for copy/move assignment. So it could only ever "elide" something that you couldn't tell the difference about. And that's not really "elision"; that's just a compiler optimization.
Objects of that class will hold enough data (say 20 doubles) that copies have to be kept to a minimum.
There's nothing stopping you from returning that Literal
type right now. You will get elision if you store the object in a new variable. And if you copy assign it to an existing variable, you won't. But that's no different from a function which returns a float that you store into an existing variable: you get a copy of the float.
So it's really up to you how much copying you want to do.
There is an important drawback to what you propose: what would happen if the constructor threw? The behaviour for that case is well defined in the standard (all data members that had already been constructed are destructed in reverse order), but how would that translate into the case where we are "constructing" the object into an already existing one?
Your example is easy because the constructor cannot throw when T = double
, but this is not so in the general case. You might end up with a half destructed object and undefined behaviour would ensue, even if your constructor and assignment operator were well behaved.
Jan Hudec's answer has a very good point about the as-if rule (+1 for him).
Hence, the assignment elision is allowed -- as he said -- provided that there's no observable effect. The fact that your assignment operator outputs "ASSIGN"
is enough to prevent the optimization.
Notice that the situation is different for copy/move constructors because the standard allows elision for copy/move constructor even if they have observable side effects (see 12.8/31).
Elision of default copy/move assignment operators is allowed based on the general as-if rule only. That is the compiler can do it if it can ascertain that it will have no observable effect on behaviour.
In practice the as-if rule is used in general fashion to allow optimizations at intermediate representation and assembly levels. If the compiler can inline the default constructor and assignment, it can optimize them. It won't ever use the code of the copy constructor for it, but for their default implementations it should end up with the same code.
Edit: I answered before there was the code sample. Copy/move constructors are elided based on explicit permission to the compiler to do so, therefore they are elided even if they have observable effect (printing "COPY"). Assignments can only be elided based on as-if rule, but they have observable effect (printing "ASSIGN"), so the compiler is not allowed to touch them.