简体   繁体   English

类数据成员ABI的std :: unique_ptr(Pimpl习惯用语)

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

I'm trying to define existing code that use "pimpl" data members to be defined with unique_ptr. 我正在尝试定义使用“ pimpl”数据成员的现有代码,以使用unique_ptr进行定义。 Some objects requires a custom deleter, and others not. 一些对象需要自定义删除器,而其他则不需要。

unique_ptr (unlike shared_ptr) destructor requires knowing a complete type of the object. unique_ptr(与shared_ptr不同)析构函数需要了解对象的完整类型。 So you need to specify the deleter in the data member declaration: 因此,您需要在数据成员声明中指定删除器:

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

When instantiating the pimpl you are constrained to using the default deleter. 实例化pimpl时,您只能使用默认的删除程序。 If you want a custom deleter, you need to specify it in the declaration 如果需要自定义删除器,则需要在声明中指定它

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

However, you can't have the option to be flexible whether you want the unique_ptr d'tor with default behaviour or a custom deleter. 但是,无论您是想要具有默认行为的unique_ptr还是自定义删除器,都无法灵活选择。 The more flexible option is the second version, but if you choose to keep with the default behaviour, then you must instantiate the unique_ptr with a specific deleter that is equivalent to the default delete, such as: 更为灵活的选项是第二个版本,但是如果选择保留默认行为,则必须使用与默认删除等效的特定删除器实例化unique_ptr,例如:

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

So, is std::unique_ptr the best way to handle ABI (compared to shared_ptr or raw pointer)? 那么,std :: unique_ptr是处理ABI的最佳方法吗(与shared_ptr或原始指针相比)?

You can easily supply a deleter that effectively calls an opaque symbol: 您可以轻松提供一个有效调用不透明符号的删除器:

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

Now you can move the definition of Foo::FooImplDelete::operator() to your source file. 现在,您可以将Foo::FooImplDelete::operator()的定义移到您的源文件中。 Indeed, an optimizing compiler will inline it into the destructor of Foo . 实际上,优化的编译器会将其内联到Foo的析构函数中。

If you have no particular reason to suspect that a custom deleter will be required, you might as well use the default; 如果没有特别的理由怀疑需要自定义删除器,则最好使用默认值。 should you ever need a custom deleter change to release the unique_ptr : 您是否需要自定义删除程序更改以release unique_ptr

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

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

Here are 2 ways that are compliant and portable. 这是两种兼容且可移植的方法。

This first is to simply manage the memory yourself (you'll see that it's trivial). 首先是简单地自己管理内存(您会发现它是微不足道的)。 The second leverages the unique_ptr 第二个利用了unique_ptr

Self managed: 自我管理:

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

using unique_ptr: 使用unique_ptr:

Foo.h: 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: 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