I will try to answer all questions immediately.
The behavior you observe is related to how the object returns by value in C ++. Firstly, the temporary object is copied (or moved to C ++ 11) from the value returned by your function. Then, if this return value is used to initialize another object, for example:
Class c = fxn();
Object c is contour-built (or motion-built, in C ++ 11) from this temporary.
Thus, it is allowed to use elide (in your particular case) or both of these calls for the copy or move constructor in accordance with paragraph 12 / 8.31 of the C ++ 11 standard, although these constructors have side effects and build the return value of the function directly in c :
When certain criteria are met, implementations are allowed to omit the copy / move construction of the object class, even if the constructor selected for the copy / move operation and / or the destructor for the object has side effects . In such cases, the implementation considers the source and purpose of the omitted copy / move as simply two different ways of accessing the same object and the destruction of this object occurs in later times, when two objects would be destroyed without optimization .122 This is the resolution of copy / move operations , called a copy, is allowed in the following cases (can be combined to eliminate multiple copies) :
- in the return expression in a function with the type of the returned class, when the expression is the name of a non-volatile automatic object ( different from the function or catch-clause parameter ) with the same cv-unqualified type as the returned type of the function, the copy / move operation can be omitted during construction an automatic object directly in a function returns a value
- [...]
- if the temporary object of the class that was not attached to the link (12.2) is copied / moved to the class object with the same cv-unqualified type, the copy / move operation can be omitted from building the temporary object directly to the target of the missed copy / move
- [...]
The reason I wrote that in your particular case only one of the calls to the copy or move constructor can be excluded is the sentence in bold in the first brochure of the above Standard Quote:
[...] (except for function parameter or catch-clause) [...]
If you return a parameter to your function, copying elision is prohibited.
Also note that the signature of your constructor should be:
Class(Class const& c)
There is no reason for you to accept the lvalue reference for non const in the copy constructor, since you are not going to modify the object from which you are copying.
Worse, the above will prevent building a copy from rvalues (e.g. temporary), so the following code will not compile:
Class foo() { return Class(); }
Although implementations are allowed to exclude a copy, there must be a viable and affordable copy constructor (or move the constructor if we are talking about relocation).