Why use copy constructors?

Jun 29, 2020 at 1:03am
I bought a C++ course on Udemy, and have been brushing up on my C++ and learning all sorts of new things as well. But I dont understand copy constructors, mainly, WHY we use them.

From what I understand, it creates an exact copy of the existing object/objects, but why is this necessary? I understand there are two subsets of this called shallow and deep copying, but my understanding of those is a little muddy, but from doing some research, shallow copying uses the same memory address and references the same objects, whereas deep copying uses separate memory addresses and any changes made to one copy will not reflect in the other

I'm not sure if my explanation of shallow and deep copying are correct, but thats what i've gathered, however I do not understand why we do this.

What would be the application of this in game design? what are some examples I would use copy constructors for? and shallow and deep copy?
Jun 29, 2020 at 2:57am
But I dont understand copy constructors, mainly, WHY we use them.
From what I understand, it creates an exact copy of the existing object/objects, but why is this necessary?

It's a strange question.
Are you really asking "why would we ever want to copy something"?
Last edited on Jun 29, 2020 at 2:58am
Jun 29, 2020 at 3:10am
well, hmm, how do i explain. I guess not so much why, but some examples of situations that this would be used in and a clearer understanding of whats going on i guess is what i need. I dont quite understand HOW to use it I guess. If I was making a game, what would copy constructors, and shallow and deep copy be used for?
Jun 29, 2020 at 3:33am
If I was making a game, what would copy constructors [...] be used for?

Again, it a strange question. They would be used to make a copy of the object. What do you think they would be used for?

what would [...] shallow and deep copy be used for?

If the object is a monolithic block of bits like this:

1
2
3
4
struct Block {
    int a, b, c;
    double e, f, g;
};

then a shallow and deep copy are the same. If instead it is made up of different (pointed-to or referred-to) subobjects then the shallow copy only copies those pointers/references and doesn't make an independent copy of the subobjects.

You almost always want a deep copy. If you only get a shallow copy of this:

1
2
3
4
struct Array {
    int*   data;
    size_t size;
};

then you don't really have a copy of the array at all. Any changes to the new array will write to the exact same data as the original. If that's what you want, fine, but it's not generally what's meant by a "copy".

As for when you might actually want a shallow copy, I wouldn't worry about it.
You'll recognize it when you see it (maybe an immutable object, or even a "copy-on-write" optimization).
Last edited on Jun 29, 2020 at 3:33am
Jun 29, 2020 at 5:36am
I wouldn't worry too much about deep copies.
They are not necessary if you don't use raw pointers and it's best pratice to avoid them.
Use STL containers and smart pointers, they implement copy and move operations
1
2
3
4
5
6
7
8
9
class Demo
{
private:
  vector<int> data;
};

Demo d1;
Demo d2(d1); // copy construction
Demo d3 = d1; // copy assignment 

Jun 29, 2020 at 9:56am
Do you ever call functions? Do you pass arguments to functions by value?
Jun 30, 2020 at 2:47am
Thanks for the replies guys. I never really use pointers other than references so deep copying isnt something I have to worry about then. I understand whats going on with copying when using functions when you pass by value and reference, so a copy constructor does the exact same thing passing by value does in a function? as in, it just creates a copy and doesnt modify the actual value?

So if I was making a program and I had an enemy, and I wanted to make a copy of it I would use a copy constructor?

The way shallow and deep copying was explained to me is shallow copying can be thought of as an excel sheet that two people are working on on two different computers at the same time, when they both enter their details, the changes will be reflected in the excel sheet, because the same excel sheet is open in both locations, both objects point to the same memory location.

Deep copying was explained like if you copy your friends test, you both will have the exact same test but if you make changes to yours, your friends test will not have those changes, because deep copying allocates separate memory.

Those explanations really made it make sense for me.

So a regular copy constructor performs shallow copying?
Last edited on Jun 30, 2020 at 2:48am
Jun 30, 2020 at 3:03am
Jun 30, 2020 at 10:57am
Ch1156 wrote:
I understand whats going on with copying when using functions when you pass by value and reference, so a copy constructor does the exact same thing passing by value does in a function? as in, it just creates a copy and doesnt modify the actual value?

Okay, you do assume that copy constructor "does same thing" as passing by value.
What determines, what passing by value does?

(You might see things differently than we do or just call them by different names. Lets see which?)
1
2
3
4
5
6
7
8
9
10
11
12
class T {
  // code
};

void foo( T val ) {
  // code
}

int main() {
  T bar;
  foo( bar );
}

The 'val' is local variable of function foo.
During function call, the 'val' is initialized with value of 'bar'.
How does the system do that initialization?
Jul 1, 2020 at 8:49am
Maybe I misunderstand the question, I'm unsure. I understand that what's happening is that when bar is passed to food parameters it will not modify whatever values are in foo function because it's being passed by value, instead of by reference. How its initialized I'm unsure, or dont remember.
Jul 1, 2020 at 3:40pm
Lets "inline" the function call:
1
2
3
4
5
6
7
8
9
10
11
class T {
  // code
};

int main() {
  T bar;
  {
    T val( bar );
    // code from foo
  }
}

That similar to what the function call does.
The argument 'val' of foo is copy constructed with the parameter (bar) that foo was called with.

Lets put it other, explicit, way:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class T {
  // code
public:
  T() = default;
  T( const T& ) = delete;
};

void foo( T val ) {
  // code
}

int main() {
  T bar;
  foo( bar ); // error
}

 In function 'int main()':
14:12: error: use of deleted function 'T::T(const T&)'
5:3: note: declared here
8:6: error:   initializing argument 1 of 'void foo(T)'

What went wrong?

We told on line 5 that the class T does not need copy constructor.
We told compiler to not create any copy constructor for T.

The result: line 14, function call with by value parameter is not possible, because T does not have copy constructor.

Conclusion: copy constructor is not "like" by value parameter.
To pass parameter by value requires copy constructor.
To pass parameter by value uses copy constructor.


You probably create more copies than you realize.
Do not ask "how to use copy constructor".
The copy constructor is the answer to "What happens when I (attempt to) create a copy?"


Copy assignment is closely related to copy constructor. The difference is that data is copied to already existing object.

Move constructor and move assignment are more recent. Rather than copy, data moves and source object is modified.
Topic archived. No new replies allowed.