簡體   English   中英

類數據成員ABI的std :: unique_ptr(Pimpl習慣用語)

[英]std::unique_ptr for class data member ABI (Pimpl idiom)

我正在嘗試定義使用“ pimpl”數據成員的現有代碼,以使用unique_ptr進行定義。 一些對象需要自定義刪除器,而其他則不需要。

unique_ptr(與shared_ptr不同)析構函數需要了解對象的完整類型。 因此,您需要在數據成員聲明中指定刪除器:

class Foo {
public:
   ...
   ~Foo (void) //in source file  =default
private:
   class FooImpl;
   std::unique_ptr <FooImpl> _pimpl;
};

實例化pimpl時,您只能使用默認的刪除程序。 如果需要自定義刪除器,則需要在聲明中指定它

class Foo {
public:
   ...
   ~Foo (void) //in source file  =default
private:
   class FooImpl;
   std::unique_ptr <FooImpl,  std::function <void (FooImpl*&)> > _pimpl;
};

但是,無論您是想要具有默認行為的unique_ptr還是自定義刪除器,都無法靈活選擇。 更為靈活的選項是第二個版本,但是如果選擇保留默認行為,則必須使用與默認刪除等效的特定刪除器實例化unique_ptr,例如:

Foo::Foo (void) :
    _impl (new CurveItemWidgetImpl, std::default_delete <FooImpl> ()) {
}

那么,std :: unique_ptr是處理ABI的最佳方法嗎(與shared_ptr或原始指針相比)?

您可以輕松提供一個有效調用不透明符號的刪除器:

class Foo {
public:
  ~Foo(); // = default
private:
  class FooImpl;
  struct FooImplDelete { void operator()(FooImpl*); };
  std::unique_ptr<FooImpl, FooImplDelete> _pimpl;
};

現在,您可以將Foo::FooImplDelete::operator()的定義移到您的源文件中。 實際上,優化的編譯器會將其內聯到Foo的析構函數中。

如果沒有特別的理由懷疑需要自定義刪除器,則最好使用默認值。 您是否需要自定義刪除程序更改以release unique_ptr

Foo::Foo() try
  : _pimpl(new FooImpl)
{
}
catch(...)
{
  delete _pimpl.release();
}

Foo::~Foo()
{
  delete _pimpl.release();
}

這是兩種兼容且可移植的方法。

首先是簡單地自己管理內存(您會發現它是微不足道的)。 第二個利用了unique_ptr

自我管理:

class Foo 
{
public:
    Foo();

    Foo(Foo&& rhs) noexcept;
    Foo(const Foo&) = delete;
    Foo& operator=(Foo&& rhs) noexcept;
    Foo& operator=(const Foo&) = delete;
    ~Foo() noexcept;
private:
    class impl;
    impl* _pimpl = nullptr;
};

// implementation:

class Foo::impl
{
    // TODO: implement your class here
};

// example constructor
Foo::Foo()
: _pimpl { new impl {} }
{}

Foo::Foo(Foo&& rhs) noexcept
: _pimpl { rhs._pimpl }
{
    rhs._pimpl = nullptr;
}

Foo& Foo::operator=(Foo&& rhs) noexcept
{
    using std::swap;
    swap(_pimpl, rhs._pimpl);
}

Foo::~Foo() noexcept
{
    // perform custom actions here, like moving impl onto a queue

    // or just delete it
    delete _pimpl;
}

使用unique_ptr:

Foo.h:

#ifndef __included__foo__h__
#define __included__foo__h__

#include <memory>

class Foo 
{
public:
    Foo();
    ~Foo();
private:
    class impl;
    std::unique_ptr<impl, void (*) (impl*) noexcept> _pimpl;
    static void handle_delete(impl*) noexcept;
};


#endif

Foo.cpp:

#include "Foo.h"

class Foo::impl
{
    // TODO: implement your class here
};

// example constructor
Foo::Foo()
: _pimpl { new impl, &Foo::handle_delete }
{

}

Foo::~Foo() = default;

void Foo::handle_delete(impl* p) noexcept
{
    // do whatever you need to do with p

    // or just delete it
    delete p;
}

暫無
暫無

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

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