模板中的pimpl-idiom;哪个智能指针?

时间:2011-12-05 14:05:47

标签: c++ templates boost pimpl-idiom scoped-ptr

我通常对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_;
};

3 个答案:

答案 0 :(得分:13)

很久以后Herb Sutter再次开始写他的GotWs。其中一个新的与“编译防火墙”有关。

您可能需要查看:

GotW #100: Compilation Firewalls (Difficulty: 6/10)

GotW #101: Compilation Firewalls, Part 2 (Difficulty: 8/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背后的动机 成语不复存在。