simford
simford

Reputation: 25

How can I write a custom deleter for an array managed by an unique_ptr?

I am trying to find a way to write a custom deleter for a C array managed by a unique_ptr in a templated C++ class. I am purposefully trying to make the class leak memory by making the deleter do nothing. In the full class, some constructors allocate the memory and some do not - rather they make use of the memory in a raw byte buffer coming from a data stream.

This is what I tried:

template <class T> class Matrix
{
    private:
    int _size;
    std::unique_ptr<T[]> _array;

    public:
    Matrix(int size, void* data) : _size(size)
                                 , _array(NULL, [](T[]* p){})
    {
        _array.reset((T*)data);
    }
};

The code does not compile, the error message is:

In file included from /tmp/test/test/test.cpp:9:
/tmp/test/test/Matrix.h:22:55: error: expected ')'
                                 , _array(NULL, [](T[]* p){})
                                                      ^
/tmp/test/test/Matrix.h:22:51: note: to match this '('
                                 , _array(NULL, [](T[]* p){})
                                                  ^
1 error generated.

Upvotes: 0

Views: 1155

Answers (2)

Caleth
Caleth

Reputation: 62636

The deleter is a template parameter of std::unique_ptr. By default it is std::default_delete, but you can specify something different, e.g.

template <typename T>
struct NonDeleter
{
    void operator()(T*) { /* nothing */ }
};

template <typename T>
struct NonDeleter<T[]> : NonDeleter<T> {};

template <class T> class Matrix
{
    private:
    int _size;
    std::unique_ptr<T[], NonDeleter<T[]>> _array;

    public:
    Matrix(int size, void* data) : _size(size)
                                 , _array(static_cast<T*>(data))
    {
    }
};

Upvotes: 0

t.niese
t.niese

Reputation: 40842

First of all, always create a simple setup to test things:

int main() {
    using T = int;

    std::unique_ptr<T[]> _array(NULL, [](T[]* p){});

    return 0;
}

So now to your problem:

  • T[]* p is not valid and should be T* p.
  • The lambda you pass as deleter does not match std::default_delete<T> which is used as default deleter. So you have to write std::unique_ptr<T[],std::function<void(T*)>.
  • And NULL might be implemented as an integral type, so you should use nullptr instead, otherwise gcc won't compile your code (since c++11 you, in general, should use nullptr instead of NULL).

So putting everything together you get:

int main() {
    using T = int;

    std::unique_ptr<T[],std::function<void(T[])>> _array(nullptr, [](T* p){});

    return 0;
}

Upvotes: 3

Related Questions