簡體   English   中英

多態unique_ptr的數組

[英]Array of polymorphic unique_ptr

使用唯一指針,我們可以寫

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.
}

但是,如果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
}

有沒有辦法實現我在這里要做的事情?

您的第一個示例具有未定義的行為,因為A沒有virtual析構函數。 unique_ptr的默認刪除器, std::default_delete是無狀態的,因此unique_ptr<A>將始終調用delete p; ,其中p的靜態類型是A*

您的代碼編譯是因為default_delete<T>復制構造函數可以接受另一個default_delete<U>實例,只要U*可以隱式轉換為T* ,在這種情況下就是這樣。 但是,當基類析構函數不是virtual時,通過基類指針對派生類對象進行多態刪除是未定義的行為。


每種類型的自定義刪除的第二個問題可以通過提供一個自定義刪除器來解決,該刪除器是一個lambda,它首先將參數轉換為適當的類型,然后再將其傳遞給該對象的刪除器。

例如,

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)); }));

vector超出范圍時,將打印:

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

現場演示

不,自定義刪除器的類型是std::unique_ptr的模板參數。 最簡單的解決方案是將成員變量添加到自定義刪除器:

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;
            //...
        }
    }
};

然后使CustomAlloc構建相應的custom_deleter並將其作為第二個參數傳遞給std::unique_ptr<A, custom_deleter>的構造函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM