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. See shared_array for that usage.

If you want to memory management for array of pointer, you have a few options depend on your requirement:

  1. Use boost::shared_array
  2. Use std::vector of boost::shared_ptr
  3. 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 with new[], and has the default deleter default_delete<Type[]>, specialized to call delete[] _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.