简体   繁体   中英

Can I rebind the deleter type for unique_ptr?

Got some questions when using the unique_ptr and tried to read the source but more questions emerge.

The template parameter Deleter in unique_ptr<class Tp, class Deleter = default_delete<Tp>> is a class other than a template so I wonder if it uses some tricks like the allocator::rebind (discussion found here ). But no, it must have an exact operator()(pointer) overload.

So I turned to the STL source (in Ubuntu 14.04 gcc 4.8) and find that a nested _Pointer class is defined for some type traits, but absolutely nothing to do with rebinding the Deleter type to something compatible with the pointer type.

// /usr/include/c++/4.8/bits/unique_ptr.h:112
class _Pointer
{
    template<typename _Up>
    static typename _Up::pointer __test(typename _Up::pointer*);

    template<typename _Up>
    static _Tp* __test(...);

    // _Dp is the Deleter type
    typedef typename remove_reference<_Dp>::type _Del;
public:
    typedef decltype(__test<_Del>(0)) type;
};

// /usr/include/c++/4.8/bits/unique_ptr.h:130
// adopt the pointer type provided by the _Pointer
typedef typename _Pointer::type   pointer;

I've no idea what that class is supposed to do but it seems the Tp parameter can be overrided. To test it I've fabricated some weird codes like this

struct MyDeleter {
    // in the deleter type, define the pointer as pointer to int
    typedef int* pointer;

    void operator()(pointer p)
    {
        delete p;
    }
};

int main()
{
    // this won't compile!
    std::unique_ptr<double, MyDeleter> p(new double(0));

    // this type is equivalent to std::unique_ptr<int, MyDeleter>
    std::unique_ptr<double, MyDeleter> p(new int(0));
    return 0;
}

I'm completely confused. Would anybody explain that

  • Is there any approach to rebind the deleter type for unique_ptr ?
  • Why is there such a mechanism to override the pointer type? Is that stated in the standard or just a "feature" in the gcc implementation?

The rules say that if MyDeleter has a nested type pointer , then that type is used. Otherwise std::unique_ptr<double, MyDeleter> will use double* formed from the first parameter.

And the pointer you store must match the resulting pointer type of the unique_ptr , otherwise the final delete would be UB.

So, in the first case of std::unique_ptr<double, MyDeleter> p(new double(0)); you try to store a double* when the deleter expects an int* . That will never work, so it's good that the compiler catches it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM