我通常对pimpl使用boost :: scoped_ptr(出于某种原因,因为如果我忘记处理复制构造函数,我就不会感到惊讶)
使用模板但是我不能将析构函数放在完全定义impl的cpp文件中,以满足scoped_ptr的析构函数的要求。无论如何它确实有效,但我不确定它是否能够保证工作或只是偶然。有一些“最佳实践”或标准吗? scoped_ptr是非可复制类中pimpls的最佳智能指针吗?
template <class T> class C {
public:
C(){}
~C(){}
private:
boost::scoped_ptr<T> pimpl_;
};
答案 0 :(得分:13)
很久以后Herb Sutter再次开始写他的GotWs。其中一个新的与“编译防火墙”有关。
您可能需要查看:
GotW #100: Compilation Firewalls (Difficulty: 6/10)
和
答案 1 :(得分:2)
两年后,我更好地了解情况,为了保持堆栈溢出答案的相关性和最新性,我今天将回答这个问题。
我原来问题的前提是有些缺陷的。使用pimpl-idiom的原因是隐藏编译器的实现细节。这是通过不透明指针(指向已声明但未定义的数据类型的指针)存储实现来完成的。这可以大大减少与类交互的其他编译单元所需的头数量,从而加快编译时间。在我的问题模板的情况下,要求在实例化时完全知道类型T,实际上要求在使用C<ImplType>
的地方完全定义impl的类型,这使得这显然不是示例经典意义上的pimpl-idiom。
通过私有指针保存类数据还有其他原因,例如,它允许轻松实现无抛出移动和交换,并且如果您的类需要实现强大的异常保证也很好(请参阅复制和交换)成语What is the copy-and-swap idiom?)。另一方面,它在每次访问impl时添加了一层间接(通常导致高速缓存未命中),并在创建和销毁impl时添加堆分配/释放。这些可能是严重的性能损失,因此这种解决方案不应被视为灵丹妙药。
如果你可以使用C ++ 11,那么应该使用std :: unique_ptr而不是boost :: scoped_ptr。
答案 2 :(得分:1)
boost::shared_ptr
除了at之外不需要完整的定义
实例化的重点 - 在构造函数中,在a的情况下
平普尔。 boost::shared_ptr
不适合pimpl习语,
但是,因为它给出了非常意外的语义(引用语义
转让或复制);如果你真的想要增加一个复杂性
智能指针,boost::scoped_ptr
会更适合(但它
确实需要在析构函数的位置进行完整定义
实例化)。
关于模板,使用pimpl习语是没有意义的
标题中的实现细节。在export
的缺席,
必须包含类模板的所有实现细节
无处不在使用模板,所以pimpl背后的动机
成语不复存在。