以下是此站点中 pImpl 习语的实现代码。
// in header file
class widget
{
public:
widget();
~widget();
private:
class impl;
unique_ptr<impl> pimpl;
};
// in implementation file
class widget::impl
{
// :::
};
widget::widget() : pimpl{ new impl{ /*...*/ } } { }
widget::~widget() { }
此外,它说以下内容:
更喜欢使用 unique_ptr 来保存 Pimpl。它比使用 shared_ptr 更有效,并且正确地表达了不应该共享 Pimpl 对象的意图。
问题:使用的效率(首选更快的移动?)究竟是什么,std::unique_ptr为什么建议不要跨多个实例共享实现?我之前问过一个关于写时复制习语的问题,为什么不在类型指针上使用 pImpl 习语的实现,shared_ptr并用以下特定于 COW 习语的运算符实现来补充它:
// Non-const * and -> , copying
T& operator*()
{
copy();
return *m_sp;
}
T* operator->()
{
copy();
return m_sp.operator->();
}
// Const * and -> methods no need to copy
const T& operator*() const
{
return *m_sp;
}
const T* operator->() const
{
return m_sp.operator->();
}
首先你需要了解shared_ptr和unique_ptr在意识形态上的区别。第一个意味着该对象将是共同所有权,而 unique_ptr 将是单独拥有的。由于 pimpl 意味着唯一所有权(当然,您不能将其共享,但这在某种程度上是不正常的),那么 unique_ptr 是正确的。
为什么更快?一切都很简单。shared_ptr 本身内部至少包含一个在原子上或带有互斥锁的引用计数器。无论哪种方式,它都不快。unique_ptr 都是不必要的。在许多情况下,编译器可以优化到与裸指针一样好的程度。
因为它不再是粉刺了。
您的实现需要一些复制功能。其次,它不是非常线程安全的。
为什么这不在 shared_ptr 中完成?因为它将是cow_ptr。这是通常不需要的额外功能(如果需要,它可能会出现在这个智能指针来自的 boost 中),并且在 C++ 中不习惯“为未使用的东西付费”。
如果您使用这些运算符完成智能指针,它将不再是
shared_ptr,而是某种cow_ptr. 是的,这也可以。这里主要是想办法把copy()它带到实现模块,因为你不能复制一个未声明的数据类型。这样的事情最终应该是这样的:
然而,实际上,复制一个对象的操作在含义上是很奇怪的。在大多数应用情况下,它是明确禁止的。如果复制在架构上是被禁止的,那么为什么会有这些实现上的困难呢?