Search code examples
c++c++11lambdaunique-ptrstd-function

Passing a custom deleter to std::unique_ptr with std::function object


I have the following working code to initialize a std::unique_ptr with a custom deleter:

class Dataset
{
    ...
private:
    class CustomGDALDatasetDeleter {
    public:
            void operator()(GDALDatasetH res) const {
                ::GDALClose(res);
            }
    };
    using ResourceType = std::unique_ptr<GDALDataset,
                                         CustomGDALDatasetDeleter>;
    ResourceType data;
};

Later I have this code:

data = ResourceType(static_cast<GDALDataset*>(::GDALOpen(filename.c_str(),
                                              static_cast<GDALAccess>(mode)))
);

When I try the same with a std::function object and lambdas I get a bad_function_call exception:

class Dataset
{
    ...
private:
    std::function<void (GDALDatasetH)> del = [](GDALDatasetH res){::GDALClose(res);};
    using ResourceType = std::unique_ptr<GDALDataset,
                                         decltype(del)>;
    ResourceType data;

};

What am I doing wrong here?


Solution

  • You are using a polymorphic function wrapper, and when default-constructing it is constructed empty.
    Thus, it throws an exception on invocation.

    function() noexcept;

    template <class A> function(allocator_arg_t, const A& a) noexcept;  
    

    2 Postconditions: !*this.

    20.9.11.2.4 function invocation [func.wrap.func.inv]

    R operator()(ArgTypes... args) const
    

    1 Effects: INVOKE (f, std::forward<ArgTypes>(args)..., R) (20.9.2), where f is the target object (20.9.1) of *this.
    2 Returns: Nothing if R is void, otherwise the return value of INVOKE (f, std::forward<ArgTypes>(args)..., R).
    3 Throws: bad_function_call if !*this; otherwise, any exception thrown by the wrapped callable object.

    Set the deleter before / at the time you first put something into data, and all is ok.