3
votes

Reading : The C++ Standard Library - A Tutorial and Reference

I came across with following piece :

Note that the default deleter provided by shared_ptr calls delete, not delete[]. This means that the default deleter is appropriate only if a shared pointer owns a single object created with new. Unfortunately, creating a shared_ptr for an array is possible but wrong:

std::shared_ptr<int> p(new int[10]); // ERROR, but compiles

So, if you use new[] to create an array of objects you have to define your own deleter. You can do that by passing a function, function object, or lambda, which calls delete[ ] for the passed ordinary pointer. For example:

std::shared_ptr<int> p(new int[10],
[](int* p) {
delete[] p;
});

Is there any specific reason behind this limitation? If shared pointer is smart, can't it be that smart that it keeps the info whether it's array or single object?

Though there is a way to do this :

std::shared_ptr<int> p(new int[10], std::default_delete<int[]>());
2
new returns a pointer, therefore the smart_ptr cannot know if the passed ptr belongs to a single instance or an array.MagunRa

2 Answers

3
votes

The issue is that new int[10] and new int return the same type: int*, so there is nothing to do any overloading on. It's a limitation inherited from C, and there isn't much that can be done about it.

Normally you would just use a container instead of directly allocating though, so it isn't usually an issue.

edit: as Richard says, and as mentioned in this question, it seems sensible that std::shared_ptr<int[]> would do as you want, since std::unique_ptr has a similar overload, and storing an actual pointer to an int[] would be kind of redundant (in any case, you could use std::shared_ptr<int*> if you really wanted to).

I still think that using default_deleter<int[]> is the best way to go as it is.

1
votes

At first glance it looks to me to be an omission in the standard. There is indeed a specialisation for array handling in std::unique_ptr so one might expect there to be one for std::shared_ptr (perhaps someone who has served on the comittee can comment?)

Here is an idiomatic way to correctly create your shared array:

#include <memory>

auto make_shared_array(std::size_t size)
{
    // create unique_ptr with correct deleter
    auto p = std::make_unique<int[]>(size);

    // take ownership of the data and a copy of the correct deleter.
    auto sp = std::shared_ptr<int>(p.release(), p.get_deleter());

    return sp;
}


int main()
{
    auto sp = make_shared_array(10);
}