簡體   English   中英

如何將unique_ptr與更通用的刪除器一起使用?

[英]How can I use unique_ptr with a more generic deleter?

考慮一些功能:

template<typename F>
void foo(F f) {
  std::unique_ptr<int> p = f();
  // do some stuff with p
}

因為unique_ptr遞減了D的默認模板參數default_delete ,所以傳遞給foo返回帶有非默認刪除器的unique_ptr任何函數對象均無法編譯。 例如,

int x = 3;
foo([&x](){
    // use empty deleter
    return std::unique_ptr<int>(&x, [](int*){});
});

但是,我可以看到這可能有用,而且我也沒有看到為什么不應該這樣做的直接原因。 有解決這個問題的通用方法嗎?

編輯

簡單的解決方法是定義foo而不是使用以下命令:

  std::unique_ptr<int, std::function<void(int*)>> p = f();

但是我想知道為什么不能將它合並到unique_ptr的接口中? 類接口不能提供此通用屬性是有原因的嗎? 是否有將這種東西“包裝”成新定義的方法?

例如,

template<typename T>
using Generic_unique_ptr =
  std::unique_ptr<
    T,
    std::function< void(typename std::unique_ptr<T>::element_type*) >
  >;

但這似乎很危險,因為它揭示了執行以下操作的潛力,

Generic_unique_ptr<int> p(new int());

這會使刪除程序未初始化並表現出不確定的行為。 也許可以通過某種方式提供std::default_delete<T> 實例作為默認刪除程序?

如果您只想在函數中使用指針,則可以使用auto關鍵字; 編譯器將推斷出已使用的unique_ptr的類型,從而自動執行正確的操作:

template <typename F>
void foo(F f)
{
    auto p = f();
    p->bar();
}

現在,根據您的評論,我們知道這不是您想要的,但是您希望能夠將unique_ptr存儲在您的類中,以便以后使用它。 這會產生一系列完全不同的問題:

  1. unique_ptr<T, D1>unique_ptr<T, D2>是不同的類型。 因此,我們需要知道您的函子F將返回什么unique_ptr<T, D>
  2. 即使我們事先知道F的返回類型,我們的類仍然只能存儲unique_ptr<T, D1>而不能存儲unique_ptr<T, D2>

解決此問題的最簡單方法(我想,可能會有更好的方法)是類型擦除

我們創建一個基類,以暴露由unique_ptr管理的指針:

template <typename T>
struct wrapper
{
    virtual ~wrapper() {}
    virtual T const * get() const = 0;
    virtual T * get() = 0;
};

從該類繼承我們的實際存儲類,該類推導了unique_ptr的類型:

template <typename T, typename F>
struct storage
    : wrapper<T>
{
    storage(F f) { p_ = f(); }
    T const * get() const { return p_.get(); }
    T * get() { return p_.get(); }

    private:
        typename std::result_of<F()>::type p_;
};

在您真正關心的類中,您現在可以存儲指向我們的基類的指針,並使用多態性來訪問基礎對象,在本例中為unique_ptr 假設我們將上面的類移到namespace detail以向用戶隱藏它們:

template <typename T>
class some_class
{
    public:
        template <typename F>
        void store(F f)
        {
            storage_.reset(new detail::storage<T, F>(f));
        }

        T const * get() const { return storage_->get(); }
        T * get() { return storage_->get(); }

    private:
        std::unique_ptr<detail::wrapper<T>> storage_;
};

您可以在此處找到一個完整的示例。

但是我想知道為什么不能將其合並到unique_ptr的接口中?

因為這樣做會把std::function的所有開銷強加給每個人 unique_ptr旨在在幾乎所有的指針擁有單個所有權的情況下很有用。 您為使用的商品付費; 並非每個使用自定義刪除器的人都需要該刪除器是通用的 這樣,他們就不必為此付費。

同樣,當前的方法允許它處理非指針資源,因為刪除器可以准確指定將哪種類型存儲在unique_ptr

如果要提供這種通用的Deleter構造,則可以創建一個(私有地)從unique_ptr繼承並復制其接口的類,減去不采用Deleter實例的構造函數。 這樣,用戶被迫傳遞刪除器功能。

暫無
暫無

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

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