Why is a public copy constructor required, even if it is not called?

Having an open copy constructor will make a small program compile, but not show the “Copy” side effect.

#include <iostream> class X { public: X(int) { std::cout << "Construct" << std::endl; } // Having a public copy constructor will make the little program // compile, but not showing the side effect "Copy". private: X(const X&) { std::cout << "Copy" << std::endl; } private: X& operator = (const X&); }; int main() { X x = 1; return 0; } 
+8
c ++ constructor oop
source share
4 answers

The following are the corresponding bits of standard C ++:

[dcl.init] / 16, bullet 6, sub-bullet 1: If the initialization is direct initialization or if it is a copy-initialization, where the cv-unqualified version of the source type is the same class, or a derived class of the class, constructor assignments are considered. ... If the constructor is not used or the resolution of the overload is ambiguous, the initialization is poorly formed. [highlighted by cursor]

In other words, it doesn't matter if compiler optimization can rob a copy, initialization is poorly formed because there are no suitable constructors. Of course, once you create a copy of constuctor public, the following section applies:

[class.copy] / 31: When certain criteria are met, implementations are allowed to omit the copy / move construct of the class object, even if the copy / move constructor and / or destructor for the object have side effects .... This is an exception for copy / move operations, called copying is allowed in the following cases (which can be combined to eliminate multiple copies):

bullet 3: if a temporary class object that was not attached to a link (12.2) is copied / moved to a class object with the same human type, the copy / move operation can be omitted by constructing a temporary object directly to the target of the missed copy / move

+4
source share

You used the so-called “copy initialization” (defined in [decl.init] ). The specific value is to create a temporary object of type X using the int constructor, and then initialize X from the temporary using the copy constructor.

However, the standard also allows for optimization, called "copy constructor resolution" (defined in [class.copy] ) in this case. If this optimization is applied, there is no temporary. X is built using the int constructor in the same way as if you wrote the so-called “direct initialization” X x(1); .

So that you do not accidentally write code that compiles when applying optimization, but not when it is not available, the standard requires that the copy constructor be accessible, even if it was deleted. Therefore, the constructor must be publicly available, although (using the compiler and the parameters you use) it is not called.

In C ++ 11, move constructors are considered, and they are also eligible. However, this class X does not have a move constructor, so C ++ 11 and C ++ 03 are the same for this example.

+8
source share

My best guess is compiler optimization. There is a valid way to declare an object this way if you have a copy constructor. Think about it explicitly:

 int main() { X x(X(1)); return 0; } 

Or more explicitly:

 int main() { X intermediate(1); X x(intermediate); return 0; } 

So instead of using operator= it knows that you are trying to initialize your object from the moment it is declared. In essence, the compiler is smart. Finally, he optimizes this step again:

 int main() { X x(1); return 0; } 

Therefore, after the compiler finds out “what you tried to do”, it becomes the standard initialization of the object.

EDIT

For completeness, note that if you try this:

 int main() { X x = 1; x = 2; return 0; } 

You will see a problem with private operator= . Obviously, it’s important to note that operator= never used in the original initialization question above, although = appears in the code.

+2
source share

Initialization is optimized by the compiler to:

 X x(1) 

This is a kind of copy that is permitted by the standard, although it can remove side effects, as you saw.

From the standard C ++ 03 12.8 section:

When certain criteria are met, the implementation may skip building a copy of the class object, even if the copy constructor and / or destructor for the object have side effects. In such cases, the implementation implies the source and purpose of the missing copy as just two different ways of accessing the same object and destroying this object at a later stage, when two objects would be destroyed without optimization. 111) This permission of copy operations is allowed in the following circumstances (which can be combined to eliminate several copies): - in isturnstatement in a function with a return type of the class, when the expression is the name of a non-volatile automatic object with the same cv-unqualified type as the return type functions, the copy operation can be omitted by creating an automatic object directly in the return value of the function - when an object of a temporary class> that is not attached to the link r Copied a class object with the same cv-unqualified type copy operation can be lowered by constructing temporal object directly at the target missing copies

The second case is what we have here.

+2
source share

All Articles