繁体   English   中英

std::unique_ptr 的自定义删除器如何工作?

[英]How does the custom deleter of std::unique_ptr work?

根据 N3290, std::unique_ptr在其构造函数中接受删除器参数。

但是,我无法在 Windows 中使用 Visual C++ 10.0 或 MinGW g++ 4.4.1,也无法在 Ubuntu 中使用 g++ 4.6.1。

因此,我担心我对它的理解不完整或错误。 我看不出明显被忽略的删除器参数的意义,所以任何人都可以提供一个有效的例子吗?

最好我也想看看它是如何用于unique_ptr<Base> p = unique_ptr<Derived>( new Derived )

可能使用标准中的一些措辞来支持该示例,即无论您使用什么编译器,它实际上都可以完成它应该做的事情?

这在 MSVC10 中对我有用

int x = 5;
auto del = [](int * p) { std::cout << "Deleting x, value is : " << *p; };
std::unique_ptr<int, decltype(del)> px(&x, del);

在 gcc 4.5 上,这里

我将跳过标准,除非您认为该示例没有完全按照您的预期执行。

为了补充所有以前的答案,有一种方法可以使用自定义删除器,而不必通过使用函数指针或类似这样的函数指针来“污染”unique_ptr 签名:

std::unique_ptr< MyType, myTypeDeleter > // not pretty

这可以通过为 std::default_delete 模板类提供特化来实现,如下所示:

namespace std
{
template<>
class default_delete< MyType >
{
public:
  void operator()(MyType *ptr)
  {
    delete ptr;
  }
};
}

现在所有“看到”这个特化的std::unique_ptr< MyType >都将被删除。 请注意,它可能不是您想要的所有std::unique_ptr< MyType > ,因此请谨慎选择您的解决方案。

我的问题已经得到很好的回答。

但以防万一人们想知道,我错误地认为unique_ptr<Derived>可以移动到unique_ptr<Base>然后记住Derived对象的删除器,即Base不需要具有虚拟析构函数. 那是错误的。 我会选择Kerrek SB 的评论作为“答案”,除非有人不能这样做来发表评论。

@Howard :下面的代码说明了一种方法来实现我认为动态分配的删除器的成本必须意味着unique_ptr支持开箱即用:

#include <iostream>
#include <memory>           // std::unique_ptr
#include <functional>       // function
#include <utility>          // move
#include <string>
using namespace std;

class Base
{
public:
    Base() { cout << "Base:<init>" << endl; }
    ~Base() { cout << "Base::<destroy>" << endl; }
    virtual string message() const { return "Message from Base!"; }
};

class Derived
    : public Base
{
public:
    Derived() { cout << "Derived::<init>" << endl; }
    ~Derived() { cout << "Derived::<destroy>" << endl; }
    virtual string message() const { return "Message from Derived!"; }
};

class BoundDeleter
{
private:
    typedef void (*DeleteFunc)( void* p );

    DeleteFunc  deleteFunc_;
    void*       pObject_;

    template< class Type >
    static void deleteFuncImpl( void* p )
    {
        delete static_cast< Type* >( p );
    }

public:
    template< class Type >
    BoundDeleter( Type* pObject )
        : deleteFunc_( &deleteFuncImpl< Type > )
        , pObject_( pObject )
    {}

    BoundDeleter( BoundDeleter&& other )
        : deleteFunc_( move( other.deleteFunc_ ) )
        , pObject_( move( other.pObject_ ) )
    {}

    void operator() (void*) const
    {
        deleteFunc_( pObject_ );
    }
};

template< class Type >
class SafeCleanupUniquePtr
    : protected unique_ptr< Type, BoundDeleter >
{
public:
    typedef unique_ptr< Type, BoundDeleter >    Base;

    using Base::operator->;
    using Base::operator*;

    template< class ActualType >
    SafeCleanupUniquePtr( ActualType* p )
        : Base( p, BoundDeleter( p ) )
    {}

    template< class Other >
    SafeCleanupUniquePtr( SafeCleanupUniquePtr< Other >&& other )
        : Base( move( other ) )
    {}
};

int main()
{
    SafeCleanupUniquePtr< Base >  p( new Derived );
    cout << p->message() << endl;
}

这有效。 破坏正确发生。

class Base
{
    public:
     Base() { std::cout << "Base::Base\n"; }
     virtual ~Base() { std::cout << "Base::~Base\n"; }
};


class Derived : public Base
{
    public:
     Derived() { std::cout << "Derived::Derived\n"; }
     virtual ~Derived() { std::cout << "Derived::~Derived\n"; }
};

void Delete(const Base* bp)
{
    delete bp;
}

int main()
{
    std::unique_ptr<Base, void(*)(const Base*)> ptr = std::unique_ptr<Derived, void(*)(const Base*)>(new Derived(), Delete);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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