1

Why exactly do we need copy constructors?

I am studying C++ and I am not able to understand the need for copy constructors , as without using a copy constructor also, i was getting correct output. I went through few examples, but it seemed to me like, it is just a good practice to have copy constructors, like to initialize variables. Could someone please help me understand the concept of copy constructors. Any help will be appreciated very much. Thank you.

Siddhant
  • 626
  • 1
  • 7
  • 20
  • 1
    Because a simple value copy (as C does it) is not sufficient for things that are not values, e.g. pointers or other handles. Write your vector as an exercise. – Peter - Reinstate Monica Feb 21 '20 at 12:50
  • Does this answer your question? [What is The Rule of Three?](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) – Duck Dodgers Feb 21 '20 at 12:51
  • Lets say you have a complex object, which needs some non-trivial code to copy. What other way of copying such an object would you suggest? The compiler won't be able to auto-generate code for it. – Some programmer dude Feb 21 '20 at 12:51
  • 2
    you dont necessarily need a copy constructor. Only when you want to copy construct objects ;). There are classes that have none – 463035818_is_not_an_ai Feb 21 '20 at 12:52
  • 1
    You can use `Foo(Foo const&) = delete;` to dispense with Foo's copy constructor. – Eljay Feb 21 '20 at 12:56
  • @Sid Do you mean that 'i can copy my object without defining copy constructor' ? Let's say for `struct foo { int x; };` – calynr Feb 21 '20 at 12:56
  • 5
    I think you are missing the fact that if you don't provide copy constructor, compiler **will generate one for you**. This applies to every `class`/`struct` in C++. Compiler generated copy-constructor is good enough for most classes, but if you manage some resources in a class (like allocating something with `new`), you need to provide your own copy-constructor. – Yksisarvinen Feb 21 '20 at 13:01
  • @Yksisarvinen This is the answer in my opinion. – lars Feb 21 '20 at 13:07
  • Why you don't ask the creator himself? - "18.3 Copying" - http://www.informit.com/articles/article.aspx?p=2216986&seqNum=3 "Copy constructors "...So, what do we do? We’ll do the obvious: provide a copy operation that copies the elements and make sure that this copy operation gets called when we initialize one vector with another. Initialization of objects of a class is done by a constructor. So, we need a constructor that copies. Unsurprisingly, such a constructor is called a copy constructor. It is defined to take as its argument a reference to the object from which to copy." – SChepurin Feb 21 '20 at 13:15
  • @lars Perhaps, but for me the question is unclear. We don't know why OP thinks copy constructors are useless, and my comment was based on a guess that they don't know that every class has a copy constructor. – Yksisarvinen Feb 21 '20 at 13:32

4 Answers4

5

Let's look at next example

#include <iostream>
struct A {
    explicit A(int value) : data_(new int[1]) { data_[0] = value; }
    ~A() { delete [] data_; }

    int getValue() const { return data_[0]; }

  private:
    int *data_ = nullptr;
};

int main() {
    A a1(1);
    A a2(2);
    a2 = a1;
    std::cout << a2.getValue() << std::endl;
}

If you execute it, the program will crash.

What happens here is you are copying the int *data_ field from a1 to a2 and then the memory allocated by a2 is leaked.

Now a1 and a2 have same pointers. And they both will call destructors to free the memory. Memory will be freed twice, which causes a crash.

Providing a correct copy constructor will solve this issue.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
Tarek Dakhran
  • 2,021
  • 11
  • 21
  • Can't reproduce. When I compile, link, and run that code, I get output of `2` and no program crash. The behaviour is actually undefined - it's misleading to say that will crash, since a crash is only one possible symptom of undefined behaviour. – Peter Feb 21 '20 at 13:27
  • You have the right idea, but `a2 = a1;` uses the assignment operator, not the copy constructor. A a2 = a1; would use the copy constructor. – user4581301 Feb 21 '20 at 15:26
5

because without using a copy constructor also, we can get the desired output

This is not actually true. You didn't write a copy constructor, but you get the desired output through a copy constructor, which your compiler writes for you:

If no user-defined copy constructors are provided for a class type (struct, class, or union), the compiler will always declare a copy constructor as a non-explicit inline public member of its class

See https://en.cppreference.com/w/cpp/language/copy_constructor for more details about implicitly declared copy constructors.


In short, the copy constructor is the function that's called when you copy an instance of your class. The compiler writes it for you but you can write it yourself if you want it to do something non-trivial (e.g. not copying a pointer but copying the object it points to)

Eternal
  • 2,648
  • 2
  • 15
  • 21
3

if you pass your objects to methods via pass by copy, c++ must use a copy constructor to generate the instance of that class for the method context. for example, if you store your instances in a vector, when you push back an object it indirectly calls the copy constructor. By the way, for classes c++ generally creates a default copy constructor if there is no explicitly implemented one, this case some times creates unwanted effects (shallow copy).

1

The rule of three (also known as the Law of The Big Three or The Big Three) is a rule of thumb in C++ (prior to C++11) that claims that if a class defines any of the following then it should probably explicitly define all three: destructor. copy constructor. copy assignment operator.

Main point: The copy constructor is necessary when you have a dynamic memory allocation (heap) in an object constructor, you need to do a copy of allocated memory to the new assigned objects also. In that way you could be able to (Obj1 = Obj2 / Obj1(Obj2) ) and guarantee the dynamic memory will be copied also.

Eduardo
  • 39
  • 10