Why is the copy constructor not called in this case?

Here is a small piece of code:

class A { public: A(int value) : value_(value) { cout <<"Regular constructor" <<endl; } A(const A& other) : value_(other.value_) { cout <<"Copy constructor" <<endl; } private: int value_; }; int main() { A a = A(5); } 

I assumed that the output would be "Regular Constructor" (for RHS), followed by a "Copy constructor" for LHS. Therefore, I avoided this style and always declared a class variable as A a(5); . But, to my surprise, in the code above, the copy constructor is never called (Visual C ++ 2008)

Does anyone know if this behavior is the result of optimizing the compiler or some documented (and portable) C ++ function? Thank.

+10
c ++ constructor copy-constructor
Nov 18 '09 at 18:40
source share
4 answers

From another comment: "Therefore, by default, I should not rely on it (since this may depend on the compiler)"

No, it is practically independent of the compiler. Any compiler standing in the sand does not waste time creating A, and then copies it.

In the standard, he explicitly says that for T = x; it is perfectly acceptable to be equivalent to the expression T(x); . (ยง12.8.15, p. 211) Doing this with T(T(x)) clearly redundant, so it removes the inner T

To get the desired behavior, you force the default compiler to build the first A:

 A a; // A is now a fully constructed object, // so it can't call constructors again: a = A(5); 
+13
Nov 18 '09 at 18:53
source share

Here you have copy-initialization of a from temporary A(5) . The implementation allowed to skip the copy constructor call here in accordance with C ++ Standard 12.2 / 2.

+4
Nov 18 '09 at 19:54
source share

I studied this in order to answer another question, which was closed as a hoax, therefore, in order to prevent the work from going to waste, I will answer this question.

The statement of the form A a = A(5) is called the copy-initialization of the variable a . Standard C ++ 11, 8.5 / 16:

The selected function is called with an initializer expression as its argument; if the function is a constructor, the call initializes the temporary version of the cv-unqualified destination type. temporary is a prvalue. The result of the call (which is temporary for the constructor) is then used for direct initialization, according to the above rules, an object that is the copy destination of the initialization. In some cases, an implementation is allowed to eliminate the copy inherent in this direct initialization by constructing an intermediate result directly in the object being initialized; see 12.2, 12.8 .

This means that the compiler is looking for an appropriate constructor to handle A(5) , creates a temporary one, and copies it to a . But under what circumstances can a copy be deleted?

See what 12.8 / 31 says:

When certain criteria are met, an implementation may skip copying / moving an object of the class, even if copying / moving the constructor and / or destructor of the object have side effects. In such cases, the implementation considers the source and the goal to omit the copy / move operation as just two different ways of accessing the same object, and the destruction of this object occurs later than the time when two objects would be destroyed without optimization. This exclusion of copy / move operations caused by a copy is permitted in the following cases: (which can be combined to eliminate multiple copies):

[...]

  • when a temporary class object that was not attached to a link (12.2) is copied / moved to a class object with the same cv-unqualified type, the copy / move operation can be skipped by creating a temporary object directly to the missed copy / move target

With all this in mind, this is what happens with the expression A a = A(5) :

  • The compiler sees a copy initialization ad
  • Constructor A(int) selected to initialize a temporary object
  • Since the temporary object is not attached to the link, and it has the same type a as the destination type in the expression to initialize the copy, the compiler is allowed to directly construct the object in a , eliding temporary
+4
Mar 30 2018-12-12T00:
source share
 A a = A(5); 

This line is equivalent

 A a(5); 

Despite the appearance of the function, the first line simply builds a with argument 5. No copy operations or temporary files are involved. From the C ++ standard, section 12.1.11:

To create new objects of this type, you can use the type conversion of functional notation (5.2.3). [Note the syntax looks like an explicit constructor call. -end note]

-one
Nov 19 '09 at 17:46
source share



All Articles