This is an example about why not to use the boost::shared_ptr with a new array with an explenation of why it will be dangerous to use.
Effectivly when using boost::shared_ptr or the normal std::shared_ptr when it releases the pointer it will always call delete. However when using new[] you need to use delete[]. This is the simple rule of when using malloc you use free. Then using new you use delete. When using new[] you need to use delete[]. Using a mixed combination will result at best a program crash. Or at worse siliently corrupting the heap and making a mess of your data.
The following code example which is using boost::shared_ptr correctly. Which is to allocate a new class and then the class will be automatically deleted once the last shared_ptr holding the reference has been removed.
#include <stdio.h>
#include <boost/shared_ptr.hpp>
class MyClass {
public:
MyClass() {
printf("MyClass Created\n");
};
~MyClass() {
printf("MyClass Deleted\n");
};
};
int main(int argc, char **argv) {
boost::shared_ptr<MyClass> ptr;
ptr.reset(new MyClass());
return 0;
}
When running under valgrind we get the following output.
==5868== Memcheck, a memory error detector
==5868== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==5868== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==5868== Command: ./a.out
==5868==
MyClass Created
MyClass Deleted
==5868==
==5868== HEAP SUMMARY:
==5868== in use at exit: 0 bytes in 0 blocks
==5868== total heap usage: 2 allocs, 2 frees, 17 bytes allocated
==5868==
==5868== All heap blocks were freed -- no leaks are possible
==5868==
==5868== For counts of detected and suppressed errors, rerun with: -v
==5868== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 19 from 8)
Once we modify the program slight to create an array of items like below. In this case ten items of "MyClass" things will change significantly.
int main(int argc, char **argv) {
boost::shared_ptr<MyClass> ptr;
ptr.reset(new MyClass[10]);
return 0;
}
When run under valgrind this will show as a memory leak. You can see that there has been ten instances of the class created but only one instance has been deleted.
==5889== Memcheck, a memory error detector
==5889== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==5889== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==5889== Command: ./a.out
==5889==
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Deleted
==5889== Invalid free() / delete / delete[]
==5889== at 0x4023881: operator delete(void*) (vg_replace_malloc.c:387)
==5889== by 0x8048CC4: void boost::checked_delete<MyClass>(MyClass*) (in /home/james/tmp/posts/a.out)
==5889== by 0x8048D3F: boost::detail::sp_counted_impl_p<MyClass>::dispose() (in /home/james/tmp/posts/a.out)
==5889== by 0x80489F7: boost::detail::sp_counted_base::release() (in /home/james/tmp/posts/a.out)
==5889== by 0x8048A69: boost::detail::shared_count::~shared_count() (in /home/james/tmp/posts/a.out)
==5889== by 0x8048ACF: boost::shared_ptr<MyClass>::~shared_ptr() (in /home/james/tmp/posts/a.out)
==5889== by 0x80488C8: main (in /home/james/tmp/posts/a.out)
==5889== Address 0x42c402c is 4 bytes inside a block of size 14 alloc'd
==5889== at 0x40243B0: operator new[](unsigned int) (vg_replace_malloc.c:299)
==5889== by 0x8048827: main (in /home/james/tmp/posts/a.out)
==5889==
==5889==
==5889== HEAP SUMMARY:
==5889== in use at exit: 14 bytes in 1 blocks
==5889== total heap usage: 2 allocs, 2 frees, 30 bytes allocated
==5889==
==5889== LEAK SUMMARY:
==5889== definitely lost: 14 bytes in 1 blocks
==5889== indirectly lost: 0 bytes in 0 blocks
==5889== possibly lost: 0 bytes in 0 blocks
==5889== still reachable: 0 bytes in 0 blocks
==5889== suppressed: 0 bytes in 0 blocks
==5889== Rerun with --leak-check=full to see details of leaked memory
==5889==
==5889== For counts of detected and suppressed errors, rerun with: -v
==5889== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 19 from 8)
However when run normally outside of valgrind using the normal c++ memory allocater in linux it will produce a heap corruption instead.
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Deleted
*** glibc detected *** ./a.out: munmap_chunk(): invalid pointer: 0x0809e00c ***
======= Backtrace: =========
/lib/i686/cmov/libc.so.6(+0x6b381)[0xb74cc381]
/lib/i686/cmov/libc.so.6(+0x6c5fe)[0xb74cd5fe]
/usr/lib/libstdc++.so.6(_ZdlPv+0x21)[0xb76a8701]
./a.out[0x8048cc5]
./a.out[0x8048d40]
./a.out[0x80489f8]
./a.out[0x8048a6a]
./a.out[0x8048ad0]
./a.out[0x80488c9]
/lib/i686/cmov/libc.so.6(__libc_start_main+0xe6)[0xb7477ca6]
./a.out[0x8048771]
======= Memory map: ========
08048000-0804a000 r-xp 00000000 08:11 4063698 /home/james/tmp/posts/a.out
0804a000-0804b000 rw-p 00001000 08:11 4063698 /home/james/tmp/posts/a.out
0809e000-080bf000 rw-p 00000000 00:00 0 [heap]
b7460000-b7461000 rw-p 00000000 00:00 0
b7461000-b75a1000 r-xp 00000000 08:01 586488 /lib/i686/cmov/libc-2.11.3.so
b75a1000-b75a2000 ---p 00140000 08:01 586488 /lib/i686/cmov/libc-2.11.3.so
b75a2000-b75a4000 r--p 00140000 08:01 586488 /lib/i686/cmov/libc-2.11.3.so
b75a4000-b75a5000 rw-p 00142000 08:01 586488 /lib/i686/cmov/libc-2.11.3.so
b75a5000-b75a8000 rw-p 00000000 00:00 0
b75a8000-b75c5000 r-xp 00000000 08:01 578602 /lib/libgcc_s.so.1
b75c5000-b75c6000 rw-p 0001c000 08:01 578602 /lib/libgcc_s.so.1
b75c6000-b75c7000 rw-p 00000000 00:00 0
[snip]
Aborted
Note that it is also possible for this to show up in valgrind as a "Mismatched free / delete / delete[]" message as well as memory leaks. Or really anything random may happen because mixing free / delete / delete[] will result in undefined behaviour.
Correcting the issue if you have come across it is easy. Simply replace the shared_ptr with a shared_array. Of course when using shared_array you can no longer use "new MyClass()" since this will then be calling delete[] instead of delete and the same problem will occur.
Here is the correct example.
#include <stdio.h>
#include <boost/shared_array.hpp>
class MyClass {
public:
MyClass() {
printf("MyClass Created\n");
};
~MyClass() {
printf("MyClass Deleted\n");
};
};
int main(int argc, char **argv) {
boost::shared_array<MyClass> ptr;
ptr.reset(new MyClass[10]);
return 0;
}
When run under valgrind you can see that it no longer leaks / crashes or complains about anything and the same number of items being created are being deleted again.
==6074== Memcheck, a memory error detector
==6074== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==6074== Using Valgrind-3.6.0.SVN-Debian and LibVEX; rerun with -h for copyright info
==6074== Command: ./a.out
==6074==
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Created
MyClass Deleted
MyClass Deleted
MyClass Deleted
MyClass Deleted
MyClass Deleted
MyClass Deleted
MyClass Deleted
MyClass Deleted
MyClass Deleted
MyClass Deleted
==6074==
==6074== HEAP SUMMARY:
==6074== in use at exit: 0 bytes in 0 blocks
==6074== total heap usage: 3 allocs, 3 frees, 54 bytes allocated
==6074==
==6074== All heap blocks were freed -- no leaks are possible
==6074==
==6074== For counts of detected and suppressed errors, rerun with: -v
==6074== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 19 from 8)