简体   繁体   English

多态unique_ptr的数组

[英]Array of polymorphic unique_ptr

Using unique pointers, we can write 使用唯一指针,我们可以写

class A{};
class B: public A{};
class C: public A{};
std::vector<std::unique_ptr<A>> myArray;
//
f()
{
    std::unique_ptr<B> pB {new B()};
    std::unique_ptr<C> pC {new C()};
    myArray.push_back(std::move(pB));
    myArray.push_back(std::move(pC));
    // nice! now I can use the interface of A without
    // worrying about its subclasses.
}

However, if classes B and C need to have their own type-dependent custom deleter: 但是,如果B类和C类需要拥有自己的类型相关的自定义删除器:

class A{};
class B: public A{};
class C: public A{};

template<class T>
struct custom_deleter
{ // roughly the same implementation as std::default_deleter
    void operator()(T* p)
    {
        CustomFree(p);
    }
};
//
std::vector<std::unique_ptr<A>> myArray; 
//
f()
{
    std::unique_ptr<B, custom_deleter<B>> pB {CustomAlloc(B())};
    std::unique_ptr<C, custom_deleter<C>> pC {CustomAlloc(C())};
    myArray.push_back(std::move(pB)); // error: can't convert to default deleter
    myArray.push_back(std::move(pC)); // item dito
}

Is there a way to achieve what I'm trying to do here? 有没有办法实现我在这里要做的事情?

Your first example has undefined behavior because A doesn't have a virtual destructor. 您的第一个示例具有未定义的行为,因为A没有virtual析构函数。 unique_ptr 's default deleter, std::default_delete is stateless, so a unique_ptr<A> will always call delete p; unique_ptr的默认删除器, std::default_delete是无状态的,因此unique_ptr<A>将始终调用delete p; , where the static type of p is A* . ,其中p的静态类型是A*

Your code compiles because the default_delete<T> copy constructor can accept another default_delete<U> instance as long as U* is implicitly convertible to T* , which it is in this case. 您的代码编译是因为default_delete<T>复制构造函数可以接受另一个default_delete<U>实例,只要U*可以隐式转换为T* ,在这种情况下就是这样。 However, polymorphic deletion of the derived class object through base class pointer, when the base class destructor is not virtual is undefined behavior. 但是,当基类析构函数不是virtual时,通过基类指针对派生类对象进行多态删除是未定义的行为。


The second problem of custom deleters for each type can be solved by supplying a custom deleter that is a lambda which first casts the argument to the appropriate type before passing it on to that object's deleter. 每种类型的自定义删除的第二个问题可以通过提供一个自定义删除器来解决,该删除器是一个lambda,它首先将参数转换为适当的类型,然后再将其传递给该对象的删除器。

For instance, 例如,

template<typename T>
void CustomDeleter(T *t)
{
    std::cout << __PRETTY_FUNCTION__ << std::endl;
    delete t;
}

std::vector<std::unique_ptr<A, void(*)(A *)>> myArray;

myArray.push_back(
    std::unique_ptr<A, void(*)(A *)>(new A(), [](A *a){ 
        CustomDeleter(a); }));
myArray.push_back(
    std::unique_ptr<A, void(*)(A *)>(new B(), [](A *a){ 
        CustomDeleter(static_cast<B*>(a)); }));
myArray.push_back(
    std::unique_ptr<A, void(*)(A *)>(new C(), [](A *a){ 
        CustomDeleter(static_cast<C*>(a)); }));

When the vector goes out of scope, this prints: vector超出范围时,将打印:

void CustomDeleter(T*) [with T = A]
void CustomDeleter(T*) [with T = B]
void CustomDeleter(T*) [with T = C]

Live demo 现场演示

No, the type of the custom deleter is a template parameter to std::unique_ptr . 不,自定义删除器的类型是std::unique_ptr的模板参数。 Your easiest solution would be to add a member variable to the custom deleter: 最简单的解决方案是将成员变量添加到自定义删除器:

struct custom_deleter
{
    int m_kind;
    custom_deleter(int kind)
    {
        m_kind = kind;
    }
    void operator()(A* p)
    {
        switch (m_kind)
        {
            case 0:
                CustomFree0(p);
                break;
            case 1:
                CustomFree1(p);
                break;
            //...
        }
    }
};

And then make CustomAlloc build the appropriate custom_deleter and pass it to the constructor of std::unique_ptr<A, custom_deleter> as second parameter. 然后使CustomAlloc构建相应的custom_deleter并将其作为第二个参数传递给std::unique_ptr<A, custom_deleter>的构造函数。

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

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