Just a simple quick question which I couldn\'t find a solid answer to anywhere else. Is the default operator= just a shallow copy of all the class\' members on the right ha
Yes, it just copies the object member-wise, which can cause issues for raw pointers.
"shallow" versus "deep" copy is less meaningful in C++ than it is in C or Java.
To illustrate this, I've changed your Foo
class from three int
s to an int
, an int*
, and a vector<int>
:
#include <iostream>
#include <vector>
class Foo {
public:
int a;
int *b;
std::vector<int> c;
};
using namespace std;
int main() {
Foo f1, f2;
f1.a = 42;
f1.b = new int(42);
f1.c.push_back(42);
f2 = f1;
cout << "f1.b: " << f1.b << " &f1.c[0]: " << &f1.c[0] << endl;
cout << "f2.b: " << f2.b << " &f2.c[0]: " << &f2.c[0] << endl;
}
When this program is run, it yields the following output:
f1.b: 0x100100080 &f1.c[0]: 0x100100090
f2.b: 0x100100080 &f2.c[0]: 0x1001000a0
The int
is boring, so I've left it out. But look at the difference between the int*
and the vector<int>
: the int*
is the same in f1 and f2; it's what you would call a "shallow copy". The vector<int>
however is different between f1 and f2; it's what you would call a "deep copy".
What's actually happened here is that the default operator =
in C++ behaves as if the operator =
for all of its members were called in order. The operator =
for int
s, int*
s, and other primitive types is just a byte-wise shallow copy. The operator =
for vector<T>
performs a deep copy.
So I would say the answer to the question is, No, the default assignment operator in C++ does not perform a shallow copy. But it also doesn't perform a deep copy. The default assignment operator in C++ recursively applies the assignment operators of the class's members.
I personally like the explanation in Accelerated c++. The text (page 201) says:
If the class author does not specify the assignment operator, the compiler synthesizes a default version. The default version is defined to operate recursively - assigning each data element according to the appropriate rules for the type of that element. Each member of a class type is assigned by calling that member's assignment operator. Members that are of built-in type are assigned by assigning their values.
As the members in the question are integers, I understand that they are deep copied. The following adaptation of your example illustrates this:
#include<iostream>
class foo {
public:
int a, b, c;
};
int main() {
foo f1, f2;
f1 = f2;
std::cout << "f1.a and f2.a are: " << f1.a << " and " << f2.a << std::endl;
f2.a = 0;
std::cout << "now, f1.a and f2.a are: " << f1.a << " and " << f2.a << std::endl;
}
which prints:
f1.a and f2.a are: 21861 and 21861
now, f1.a and f2.a are: 21861 and 0
I'd say, default operator=
is a copy. It copies each member.
The distinction between a shallow copy and a deep copy doesn't arise unless the members being copied are some kind of indirection such as a pointer. As far as the default operator=
is concerned, it's up to the member being copied what "copy" means, it could be deep or shallow.
Specifically, though, copying a raw pointer just copies the pointer value, it doesn't do anything with the referand. So objects containing pointer members are shallow-copied by default operator=
.
There are various efforts at writing smart pointers that perform clone operations on copying, so if you use those everywhere in place of raw pointers then the default operator=
will perform a deep copy.
If your object has any standard containers as members, then it may be confusing to (for example) a Java programmer to say that operator=
is a "shallow copy". In Java a Vector
member is really just a reference, so "shallow copy" means that Vector
members aren't cloned: source and destination refer to the same underlying vector object. In C++ a vector
member will be copied, along with its contents, since the member is an actual object not a reference (and vector::operator=
guarantees the contents are copied with it).
If your data member is a vector of pointers, then you don't have either a deep copy or a shallow copy. You have a semi-deep copy, where the source and destination objects have separate vectors, but the corresponding vector elements from each still point to the same, uncloned object.
No. operator=
doesn't perform a copy at all. It's an assignment operator, not copy operator.
The default assignment operator assigns each member.
If a, b and c were classes then the assignment operator for those classes would be called, so the compiler isn't simply copying the raw memory contents - but as others pointed out, any raw pointers will be copied without any attempt to duplicate the pointed-to thing, thus giving you the potential for dangling pointers.