'What is the use of a custom unique_ptr deleter that calls delete?

In the C++ samples provided by NVidia's TensorRT library, there is a file named common.h that contains definitions of structures used throughout the examples.

Among other things, the file contains the following definitions:

struct InferDeleter
{
    template <typename T>
    void operator()(T* obj) const
    {
        delete obj;
    }
};

template <typename T>
using SampleUniquePtr = std::unique_ptr<T, InferDeleter>;

The SampleUniquePtr alias is used throughout the code samples to wrap various pointers to interface classes returned by some functions, e.g. SampleUniquePtr<INetworkDefinition>(builder->createNetworkV2(0));

My question is, in what practical aspects are std::unique_ptr and SampleUniquePtr different? The behavior of SampleUniquePtr is pretty much what I would expect from std::unique_ptr, at least now. Could it be for compatibility with old versions of C++?



Solution 1:[1]

I don't have the time to scan through the entirety of the linked library, so there is a chance I'm wrong on this count.

But, what you're seeing is probably a default implementation that's used as a fallback for any type that doesn't need special handling.

The Library Implementor always has the option of specializing this function in the situation where they're dealing with a type that actually does need special handling, which is probably pretty common for a library made by Nvidia (and therefore probably meant to interact with the GPU).

class GPUResource {
//...
~GPUResource() noexcept {} //Does NOT perform the special handling, for whatever library-specific reason
};

template<>
void InferDeleter::operator()<GPUResource>(GPUResource * obj) {
    performSpecialCleanupOnGPUResource(obj->handle);
    delete obj;
}

In practice, this kind of stuff always smells like an anti-pattern (are you sure, Library Implementor, that you couldn't do the cleanup in the destructor of this object??) but if they had good reasons for separating out the logic like this, the way they've defined InferDeleter permits them this kind of flexibility.

Solution 2:[2]

The example looks pointless as that is exactly what I expect the default deleter to do.

But maybe this is better (untested):

#include <vector>
struct VectorDeleter
{
    template <typename T>
    void operator()(std::vector<T*> *v) const
    {
        for(auto p : *v) delete p;
        delete v;
    }
};

template <typename V>
using UniquePtrVector = std::unique_ptr<V, VectorDeleter>;

When you have a vector of pointers (to e.g. polymorphic classes) you have to delete the objects the vector points to when the vector is deleted. The VectorDeleter does that before the vector itself is deleted.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Xirema
Solution 2 Goswin von Brederlow