Signature C ++ copy constructor: matters

In my current implementation, there are many copy constructors with this syntax

MyClass::Myclass(Myclass* my_class)

Is this (functionnaly) really different from

MyClass::MyClass(const MyClass& my_class)

and why?

I was informed that the first solution was not a true copy constructor. However, making changes involves quite a bit of refactoring.

Thanks!!!

+6
source share
5 answers

This differs in that the former is not a copy constructor, but a transformation constructor. It converts from MyClass* to MyClass .

By definition, a copy instance has one of the following signatures:

 MyClass(MyClass& my_class) MyClass(const MyClass& my_class) //.... //combination of cv-qualifiers and other arguments that have default values 

12.8. Copy class objects

2) A constructor without a template for class X is a copy constructor if its first parameter is of type X &, const X &, mutable X & or const volatile X &, and either there are no other parameters, or all other parameters have default arguments (8.3 .6) .113) [Example: X :: X (const X &) and X :: X (X &, int = 1) are copy constructors.

EDIT: you seem to be confusing the two.

Say what you have:

 struct A { A(); A(A* other); A(const A& other); }; A a; //uses default constructor A b(a); //uses copy constructor A c(&a); //uses conversion constructor 

They serve for different purposes all together.

+16
source

The first version is not a copy constructor. Just like that. This is just another constructor.

The copy constructor for class X must have the signature (X &, ...) or (X const &, ...) or (X volatile &, ...) or (X const volatile &, ...) , where everything arguments, except the first, have default values ​​if they are present (and this should not be a template).


However, you should carefully consider why you are violating the Zero rule: most well-designed classes should not have any user-defined copy constructors, copy statements, or destructor in general, but instead rely on well-designed members. The fact that your current constructor accepts a pointer makes you wonder if your code is behaving somehow like MyClass x = y; - worth checking out.

+7
source

Some language constructs require a copy constructor:

  • transmission by value
  • return by value
  • Initializing the copy style (although a copy is often copied in this case)

If the language calls the copy, and you provided the copy constructor, then it can be used (provided that the cv-qualifications are in order, of course).

Since you did not provide a copy constructor, you will get a copy constructor created by the compiler instead. This works by copying each data item, even if it is not suitable for your class. For example, if your not-a-copy constructor explicitly makes any deep copies or allocates resources, you need to suppress the copy generated by the compiler.

If the copy created by the compiler works for your class, then your non-copy constructor is basically harmless. I do not think this is a particularly good idea:

 void some_function(const MyClass &foo); MyClass *ptr = new MyClass(); const MyClass *ptr2 = ptr; some_function(ptr); // compiles, but copies *ptr and uses the copy MyClass bar(ptr2); // doesn't compile -- requires pointer-to-non-const 

Even assuming that the copy created by the compiler is not suitable for your class, a lot of refactoring is not required to make the necessary changes. Suppose your non-constructor does not actually modify the object that its argument points to, so after correcting your signature:

 MyClass::MyClass(const MyClass* my_class) { // maybe treat null pointer specially // do stuff here } 

You need:

 MyClass::MyClass(const MyClass& my_class) { do_stuff(my_class); } MyClass::MyClass(const MyClass* my_class) { // maybe treat null pointer specially do_stuff(*my_class); } MyClass::do_stuff(const MyClass& my_class) { // do stuff here } 

You also need to copy any initializer list from the old constructor to the new one and change it so that my_class not a pointer to the new one.

Removing the old constructor may require a lot of refactoring, since you need to edit any code that uses it. However, you do not need to remove the old constructor to fix any problems with the default copy constructor.

+5
source

The first example is not a copy constructor. This means that when provided, the compiler still provides a default copy constructor with a signature equivalent to

 MyClass(const MyClass& my_class); 

If you are doing something special with your constructor, and the compiler provided by the copy constructor does not follow this logic, you must either implement the copy constructor or find a way to disable it.

+1
source

Why do I want to use the copy constructor instead of the transform constructor?

This can be problematic if you give MyClass objects some code that expects your copy constructor to be valid.

This applies to STL containers. For example, if you use std::vector<MyClass> , you should know that vectors are allowed to move elements for redistribution using their copy constructors.

The default constructor provided by the compiler will execute a shallow copy, invoking copy constructors of all attributes, making simple copies for the base type, such as pointers. If you need a deep copy form, you will have to rewrite the copy constructor MyClass correctly

+1
source

Source: https://habr.com/ru/post/926743/


All Articles