Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++ copy constructor signature : does it matter

My current implementation uses lots of copy constructors with this syntax

MyClass::Myclass(Myclass* my_class)

Is it really (functionnaly) different from

MyClass::MyClass(const MyClass& my_class)

and why?

I was adviced that first solution was not a true copy constructor. However, making the change implies quite a lot of refactoring.

Thanks!!!

like image 783
kiriloff Avatar asked Oct 02 '12 10:10

kiriloff


People also ask

What is the correct signature for the constructor?

Constructors have no return type and always use the name of the class in which they are declared [3]. Similarly to method signatures, a constructor signature is made up of the constructor name and a comma-delimited list of input parameters enclosed in parentheses.

What is the requirement of copy constructor?

A user-defined copy constructor is generally needed when an object owns pointers or non-shareable references, such as to a file, in which case a destructor and an assignment operator should also be written (see Rule of three).

What are the disadvantages of copy constructor?

The only disadvantage I can think of to a copy constructor is that some large objects can be expensive to copy (eg. copying a long string involves allocating a large block of memory then copying all the content).

Should copy constructors be const?

When we create our own copy constructor, we pass an object by reference and we generally pass it as a const reference. One reason for passing const reference is, we should use const in C++ wherever possible so that objects are not accidentally modified.


5 Answers

It's different in the sense that the first isn't a copy constructor, but a conversion constructor. It converts from a MyClass* to a MyClass.

By definition, a copy-constructor 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. Copying class objects

2) A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else 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 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 different purposes alltogether.

like image 180
Luchian Grigore Avatar answered Oct 16 '22 16:10

Luchian Grigore


The first version is not a copy constructor. Simple as that. It's just another constructor.

A copy constructor for a class X must have signature (X &, ...) or (X const &, ...) or (X volatile &, ...) or (X const volatile &, ...), where all arguments but the first have default values if they are present (and it must not be a template).


That said, you should think very carefully about why you're violating the Rule of Zero: Most well-designed classes shouldn't have any user-defined copy-constructor, copy-assignment operator or destructor at all, and instead rely on well-designed members. The fact that your current constructor takes a pointer makes me wonder if your code behaves correctly for something like MyClass x = y; — worth checking.

like image 33
Kerrek SB Avatar answered Oct 16 '22 16:10

Kerrek SB


Certain language constructs call for a copy constructor:

  • passing by value
  • returning by value
  • copy-style initialization (although the copy is often elided in that case)

If the language calls for a copy, and you have provided a copy constructor, then it can be used (assuming the cv-qualifications are OK, of course).

Since you have not provided a copy constructor, you will get the compiler-generated copy constructor instead. This works by copying each data member, even if that's not the right thing to do for your class. For example if your not-a-copy-constructor explicitly does any deep copies or allocates resources, then you need to suppress the compiler-generated copy.

If the compiler-generated copy works for your class, then your not-a-copy-constructor is mostly harmless. I don't think it's a particularly good idea, though:

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 compiler-generated copy is no good for your class, making the necessary change need not require a lot of refactoring. Suppose that your not-a-constructor doesn't actually modify the object pointed to by its argument, so after fixing the signature you have:

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 modify it for the fact that my_class isn't a pointer in the new one.

Removing the old constructor might require a lot of refactoring, since you have to edit any code that uses it. You don't have to remove the old constructor in order to fix any problems with the default copy constructor, though.

like image 39
Steve Jessop Avatar answered Oct 16 '22 17:10

Steve Jessop


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

MyClass(const MyClass& my_class);

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

like image 28
juanchopanza Avatar answered Oct 16 '22 16:10

juanchopanza


Why would I want to use a copy constructor instead of a conversion constructor?

It can be problematic if you give MyClass objects to some code that expect your copy-constructor to be valid.

This is the case for STL containers. For instance, if you use a std::vector<MyClass>, you must be aware that vectors are allowed to move elements around for reallocation using their copy constructors.

The default constructor provided by the compiler will perform a shallow copy, calling copy constructors of every attributes, making simple copies for base type like pointers. If you want some form of deep copy you will have to properly rewrite the copy constructor of MyClass

like image 23
log0 Avatar answered Oct 16 '22 15:10

log0