I have implemented a function where the identity is given to me and out of my control. It returns std::shared_ptr<const void>
. In the function i allocate an arbitrary amount of memory, and return access to it though the shared_ptr.
My memory allocation is done with new unsigned char[123]
. The problem is that valgrind detects a mismatch between the usage of new and delete variants. While i use new[](unsigned)
to allocate memory, the shared_ptr destructor uses delete(void*)
to deallocate it, and valgrind warns whenever you are using the "incorrect" deallocator for an allocation.
In more practical terms, i wrote this test case to show what i mean:
TEST(Example, Test1)
{
unsigned char* mem = new unsigned char[123];
std::shared_ptr<const void> ptr(mem);
}
The valgrind report says
==45794== Mismatched free() / delete / delete []
==45794== at 0x4C2A64B: operator delete(void*) (vg_replace_malloc.c:576)
==45794== by 0x40B7B5: _M_release (shared_ptr_base.h:150)
==45794== by 0x40B7B5: ~__shared_count (shared_ptr_base.h:659)
==45794== by 0x40B7B5: ~__shared_ptr (shared_ptr_base.h:925)
==45794== by 0x40B7B5: ~shared_ptr (shared_ptr.h:93)
==45794== by 0x40B7B5: Example_Test1_Test::TestBody() (test.cc:108)
==45794== Address 0x5cb6290 is 0 bytes inside a block of size 123 alloc'd
==45794== at 0x4C29CAF: operator new[](unsigned long) (vg_replace_malloc.c:423)
==45794== by 0x40B72E: Example_Test1_Test::TestBody() (test.cc:107)
I want to avoid valgrind filters if possible.
What is the correct way to allocate an arbitrary amount of data and return as a std::shared_ptr<const void>
?
To allocate memory to an object, we must use new(). So the object is always allocated memory on the heap (See this for more details).
C uses the malloc() and calloc() function to allocate memory dynamically at run time and uses a free() function to free dynamically allocated memory. C++ supports these functions and also has two operators new and delete, that perform the task of allocating and freeing the memory in a better and easier way.
A shared_ptr may share ownership of an object while storing a pointer to another object. get() returns the stored pointer, not the managed pointer.
So 1000 shared pointers take up 1000 * 2 * sizeof(pointer) bytes of memory. Size of a pointer is 4 bytes on all 32-bit systems that follow ILP32 data model.
If you give shared_ptr<T>
a T
pointer, it assumes that you created a single object and implies the deleter delete p;
. If your allocation was actually performed with array-new, you need to pass an appropriate deleter that performs delete[] p;
. You can reuse std::default_delete
if you like:
return static_pointer_cast<const void>(
std::shared_ptr<unsigned char>(
new unsigned char[N],
std::default_delete<unsigned char[]>()));
(You don't even need the outer cast, since the conversion is implied.)
In C++17, shared_ptr
supports arrays, so you can say
shared_ptr<unsigned char[]>(new unsigned char[N])
there and get the correct deleter (and then convert to void).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With