How do smart pointers choose between delete and delete[]?
std::unique_ptr
is not meant for array as I quote latest boost document:
Normally, a
shared_ptr
cannot correctly hold a pointer to a dynamically allocated array. Seeshared_array
for that usage.
If you want to memory management for array of pointer, you have a few options depend on your requirement:
- Use
boost::shared_array
- Use
std::vector
ofboost::shared_ptr
- Use boost pointer container like
boost::ptr_vector
Unfortunately, they don't know what delete to use therefore they use delete
. That's why for each smart pointer we have a smart array counterpart.
std::shared_ptr uses delete
std::shared_array uses delete[]
So, your line
std :: unique_ptr <int> x (new int [2]);
actually causes undefined behavior.
Incidentally, if you write
std :: unique_ptr<int[]> p(new int[2]);
^^
then delete[]
will be used since you've explicitly requested that. However, the following line will still be UB.
std :: unique_ptr<int[]> p(new int);
The reason that they can't choose between delete
and delete[]
is that new int
and new int[2]
are exactly of the same type - int*
.
Here's a related question of using correct deleters in case of smart_ptr<void>
and smart_ptr<Base>
when Base
has no virtual destructor.
From Microsoft's documentation:
(A partial specialization
unique_ptr<Type[]>
manages array objects allocated withnew[]
, and has the default deleterdefault_delete<Type[]>
, specialized to calldelete[] _Ptr
.)
I added the two final square brackets, seems like a typo as it doesn't make sense without them.
There is no "magical" way to detect whether a int*
refers to:
- a single heap allocated integer
- a heap allocated array
- an integer in a heap allocated array
The information was lost by the type system and no runtime method (portable) can fix it. It's infuriating and a serious design flaw (*) in C that C++ inherited (for the sake of compatibility, some say).
However, there are some ways of dealing with arrays in smart pointers.
First, your unique_ptr
type is incorrect to deal with an array, you should be using:
std::unique_ptr<int[]> p(new int[10]);
which is meant to call delete[]
. I know there is talk of implementing a specific warning in Clang to catch obvious mismatches with unique_ptr
: it's a quality of implementation issue (the Standard merely says it's UB), and not all cases can be covered without WPA.
Second, a boost::shared_ptr
can have a custom deleter which could if you design it to call the correct delete[]
operator. However, there is a boost::shared_array
especially designed for this. Once again, detection of mismatches is a quality of implementation issue. std::shared_ptr
suffers the same issue (edited after ildjarn's remark).
I agree that it's not pretty. It seems so obnoxious that a design flaw (*) from the origins of C haunts us today still.
(*) some will say that C leans heavily toward avoiding overhead and this would have added an overhead. I partly disagree: malloc
always know the size of the block, after all.