我正在尝试定义使用unique_ptr定义的使用“pimpl”数据成员的现有代码。某些对象需要自定义删除器,而其他对象则不需要。
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 d'tor具有默认行为或自定义删除器,则无法灵活选择。更灵活的选项是第二个版本,但如果您选择保留默认行为,则必须使用与默认删除等效的特定删除实例化unique_ptr,例如:
Foo::Foo (void) :
_impl (new CurveItemWidgetImpl, std::default_delete <FooImpl> ()) {
}
那么,std :: unique_ptr是处理ABI的最佳方式(与shared_ptr或raw指针相比)吗?
答案 0 :(得分:3)
您可以轻松提供有效调用不透明符号的删除器:
class Foo {
public:
~Foo(); // = default
private:
class FooImpl;
struct FooImplDelete { void operator()(FooImpl*); };
std::unique_ptr<FooImpl, FooImplDelete> _pimpl;
};
现在,您可以将Foo::FooImplDelete::operator()
的定义移动到源文件中。实际上,优化编译器会将其内联到Foo
的析构函数中。
如果您没有特别的理由怀疑需要自定义删除器,您也可以使用默认值;您是否需要自定义删除器更改为release
{/ 1}} {/ 1>
unique_ptr
答案 1 :(得分:2)
以下是两种兼容和便携的方式。
首先是自己简单地管理记忆(你会发现它是微不足道的)。第二个利用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;
}