Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way to allocate memory to std::shared_ptr

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>?

like image 336
Martin G Avatar asked Mar 08 '17 05:03

Martin G


People also ask

Which is the best way to allocate memory for any object?

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).

How do you allocate memory in C++?

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.

What does shared_ptr get () do?

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.

How much memory do 1000 shared pointers take?

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.


1 Answers

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).

like image 95
Kerrek SB Avatar answered Sep 24 '22 17:09

Kerrek SB