Reputation: 393
I want use shared_ptr to manage dynamically allocated arrays. Before I learnt the existence of STL allocator, I always used new[] to allocate memory and write a deleter for shared_ptr to free it. The code then would look like:
struct ArrayDeleter
{
void operator()(int* p) { delete [] p; }
};
...
...
std::shared_ptr<int> array(new int[100], ArrayDeleter());
...
Without the ArrayDeleter to free memory, tools like valgrind will report memory error for unbalanced new[] and delete[]. I understand this problem is caused by shared_ptr calling delete
instead of delete[]
to free the memory.
However, I wonder if it is the same case for memory allocated by an allocator. I had my code look like:
std::allocator<int> alloc;
std::shared_ptr<int> array(alloc.allocate(10));
...
So no specific deleter is provided in the code. Then I checked the program using valgrind, but this time, it didn't complain anything. So can I safely assume std::allocator is implemented to use new
to allocate memory, so that the default delete
operator used by std::shared_ptr is fine with it?
What about I implemented my own allocators? Am I right that a customised allocator that doesn't use new operator will break the above code, i.e I still need a deleter?
Upvotes: 2
Views: 240
Reputation: 279255
can I safely assume std::allocator is implemented to use new to allocate memory, so that the default delete operator used by std::shared_ptr is fine with it?
No, you cannot. The default std::allocator<T>
is defined to allocate the memory using global ::operator new
, but I don't think it's required that each call to allocate
results in exactly one call to ::operator new
, or that the value returned from allocate()
is equal to the value returned from new
.
The correct way to free the memory is by calling deallocate()
on the allocator, which will use global ::operator delete
.
So, your code is not freeing the data correctly. It just happens to work in your implementation that std::allocator
isn't doing anything special with the allocations, and that calling delete
on an int*
behaves the same as calling global operator delete
. It could fail for other types or on other implementations.
Also, allocate()
does not initialize the objects, so calling delete
would call the destructor for some memory that was never constructed. This has undefined behavior if the type is not trivial (int
is trivial, though).
Your code is not necessarily correct for custom allocators either, for the same reasons.
Upvotes: 2