Programmer-Defined Data Types 267
p1 -> name = strdup ( p2 -> name );21
return p1;22
}23
int main ( i n t argc , char * argv [])24
{25
Person * p1 = P erson _const ruct (1989 , 8, 21 , " Amy ") ;26
Person * p2 = P erson _const ruct (1991 , 2, 17 , " Jennifer ") ;27
Person * p3 = P erson_cop y ( p1 ); // create p328
Perso n_print ( p1 );29
Perso n_print ( p2 );30
Perso n_print ( p3 );31
p3 = P e rson_a ssign (p3 , p2 );32
Perso n_print ( p3 );33
Pers on_des truct ( p1 );34
Pers on_des truct ( p2 );35
Pers on_des truct ( p3 );36
return EXIT _SUCCES S ;37
}38
What is the difference between Person copy and Person assign? Person copy creates
a new Person object by allocating memory. Person assign has to release memory for
existing attributes before copying the attributes.
The copy constructor allocates separate memory space so that changing one object later
does not affect the other. This is called a deep copy. The assignment function has to do
more work, because the object already occupies memory. In our example, the original name
in p3 is “Amy”. When p2 is copied to p3, p3 -> name does not have enough memory for
the longer name “Jennifer”. Thus, the assignment function first releases the memory for
p3 -> name and then allocates memory again by later calling strdup.
The assignment function can check whether p3 -> name has enough memory. If
p3 -> name has enough memory, it is unnecessary to release p3 -> name and allocate
memory again. Note that this would require an if statement and a call of strlen. This can
marginally complicate the program. If the new name is longer, it is still necessary to free and
allocate memory. Some beginner programmers want to optimize their code. However, it is
often difficult for even experienced programmers to know what is slowing down a program.
You should avoid making this type of unnecessary complication without first profiling the
code using gprof. This is a very important principle to follow.
Whereas a deep copy allocates memory so that objects do not share memory, a shallow
copy allows several objects’ attributes to point to the same memory addresses. Shallow
copies can be useful in some cases. For example, in a student database, every student has an
attribute that points to an object representing the school. It is unnecessary for every student
to have an individual copy of the school’s object. There can be one school object shared by
every student object. In this scenario sharing makes sense, and the copy constructor and
assignment operator should perform a shallow copy of the school attribute. Another reason
for using shallow copies is when objects share a very large piece of memory and few objects
actually need to modify this shared memory. A copy is made only when an object intends
to make changes. This is called copy on write and is beyond the scope of this book.