I am trying to create a class that holds a dynamically created variable. My class currently looks pretty much like this:
class Foo
{
private:
int *dynamic_int;
public:
Foo ()
{
dynamic_int = new int;
}
~Foo ()
{
delete dynamic_int;
}
};
Creating an instance the class causes no problems. The following script works like charm:
int main ()
{
Foo a;
return 0;
}
However, copying the variable causes the program to crash:
int main ()
{
Foo a;
Foo b;
b = a;
return 0;
}
… returns …
*** glibc detected *** ./tester: double free or corruption (fasttop): 0x000000000081a010 ***
======= Backtrace: =========
/lib64/libc.so.6[0x3b5cc7c2d6]
./tester[0x40072b]
./tester[0x4006ca]
/lib64/libc.so.6(__libc_start_main+0xed)[0x3b5cc2169d]
./tester[0x4005c9]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:03 15074305 /home/jakob/Projects/c++ tester/tester
00600000-00601000 rw-p 00000000 08:03 15074305 /home/jakob/Projects/c++ tester/tester
0081a000-0083b000 rw-p 00000000 00:00 0 [heap]
3b5c800000-3b5c822000 r-xp 00000000 08:01 132754 /lib64/ld-2.14.90.so
3b5ca21000-3b5ca22000 r--p 00021000 08:01 132754 /lib64/ld-2.14.90.so
3b5ca22000-3b5ca23000 rw-p 00022000 08:01 132754 /lib64/ld-2.14.90.so
3b5ca23000-3b5ca24000 rw-p 00000000 00:00 0
3b5cc00000-3b5cdab000 r-xp 00000000 08:01 136046 /lib64/libc-2.14.90.so
3b5cdab000-3b5cfab000 ---p 001ab000 08:01 136046 /lib64/libc-2.14.90.so
3b5cfab000-3b5cfaf000 r--p 001ab000 08:01 136046 /lib64/libc-2.14.90.so
3b5cfaf000-3b5cfb1000 rw-p 001af000 08:01 136046 /lib64/libc-2.14.90.so
3b5cfb1000-3b5cfb6000 rw-p 00000000 00:00 0
3b5dc00000-3b5dc83000 r-xp 00000000 08:01 136047 /lib64/libm-2.14.90.so
3b5dc83000-3b5de82000 ---p 00083000 08:01 136047 /lib64/libm-2.14.90.so
3b5de82000-3b5de83000 r--p 00082000 08:01 136047 /lib64/libm-2.14.90.so
3b5de83000-3b5de84000 rw-p 00083000 08:01 136047 /lib64/libm-2.14.90.so
3b5e400000-3b5e415000 r-xp 00000000 08:01 162165 /lib64/libgcc_s-4.6.2-20111027.so.1
3b5e415000-3b5e614000 ---p 00015000 08:01 162165 /lib64/libgcc_s-4.6.2-20111027.so.1
3b5e614000-3b5e615000 rw-p 00014000 08:01 162165 /lib64/libgcc_s-4.6.2-20111027.so.1
3b64400000-3b644e9000 r-xp 00000000 08:01 167743 /usr/lib64/libstdc++.so.6.0.16
3b644e9000-3b646e8000 ---p 000e9000 08:01 167743 /usr/lib64/libstdc++.so.6.0.16
3b646e8000-3b646f0000 r--p 000e8000 08:01 167743 /usr/lib64/libstdc++.so.6.0.16
3b646f0000-3b646f2000 rw-p 000f0000 08:01 167743 /usr/lib64/libstdc++.so.6.0.16
3b646f2000-3b64707000 rw-p 00000000 00:00 0
7f94cd77e000-7f94cd783000 rw-p 00000000 00:00 0
7f94cd79f000-7f94cd7a1000 rw-p 00000000 00:00 0
7fffab7e7000-7fffab808000 rw-p 00000000 00:00 0 [stack]
7fffab881000-7fffab882000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
The problem itself seems pretty clear to me:
When assigning a’s value to b the instance itself gets copied but the pointer called “dynamic_int” of both instances points to the same adress. At the end of the “main” function both instances get destroyed. This results in double deletion of the dynamically allocated variable.
How can (and should) I handle this? What is a clean way to handle this?
Each C++ class has a copy constructor, which is invoked when an instance of that class needs to be copied. Similarly, when an instance is assigned (as in your example), an assignment operator gets called.
If you don’t define a copy constructor or an assignment operator explicitly, default implementations are generated by the compiler, which simply copy all members.
In this case, this is not the correct behavior, since
Fooexclusively owns thedynamic_intpointer, as indicated by the fact that it unconditionally deletes it on destruction.So you need to implement both a copy constructor and an assignment operator to enforce the correct copy semantics, for example:
The rule of three is good to keep in mind and applies well here: you have special destruction behavior, so it’s likely that you need custom copying behavior as well.