2011-12-05 24 views
6

我通常使用一个boost :: scoped_ptr的为平普尔的(原因之一,因为那时我没有得到的惊喜,如果我忘了处理拷贝构造函数)模板中的pimpl-idiom;哪个智能指针?

有了模板,但我不能只是把析构函数为了满足scoped_ptr析构函数的要求,impl被完全定义的cpp文件。无论如何它确实有效,但我不确定它是否可以保证工作或偶然。有一些'最佳实践'或标准吗? scoped_ptr是不可复制类中pimpls的最佳智能指针吗?

template <class T> class C { 
public: 
    C(){} 
    ~C(){} 
private: 
    boost::scoped_ptr<T> pimpl_; 
}; 
+4

这种PIMPL实现没有任何意义,因为为了实例化C模板,您必须知道类型T. PIMPL另一方面完全隐藏了用户的T等价物。 – 2011-12-05 14:11:31

+0

@VladLazarenko嗯,我认为boost :: scoped_ptr也适用于预先声明的类。在这种情况下,它取决于T是否被定义或预先声明。这个scoped_ptr的实例将隐藏在实现中(pimpl_(new T())。 –

+0

@DavidFeurle:实际上,为了使这个模板起作用,'T'的大小以及它的接口必须是因为“客户端”需要实例化模板,例如,你在哪里调用'new T()'?你不能将它隐藏在“cpp”文件中,因为它必须在模板中,所以它不是PIMPL – 2011-12-05 14:19:20

回答

1

boost::shared_ptr不需要比 实例—在点以外的完整的定义构造函数,在012xxpimpl的情况下。 boost::shared_ptr不是适合于pimpl习语, 然而,因为它提供了非常意想不到的语义(参考语义 分配或复制);如果你真的想要增加一个智能指针的复杂度,boost::scoped_ptr会更合适(但它的 确实需要一个完整的定义,其析构器被实例化为 )。

关于模板,使用pimpl idiom为 头部的实现细节是没有意义的。在缺少export, 的情况下,类模板的所有实现细节必须包含在使用模板的任何地方,因此pimpl 成语背后的动机不复存在。

13

刚刚发生的事情是Herb Sutter在很长一段时间后开始写他的GotWs。其中第一个与“编译防火墙”有关。

你可能想看一看:

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

GotW #101: Compilation Firewalls, Part 2 (Difficulty: 8/10)

+0

酷我喜欢他的书籍,他似乎回答了我使用unique_ptr。 – odinthenerd

+0

作答的使用指针类型的问题:'' unique_ptr pimpl' – sehe

+1

看起来像Herb's买入更复杂的是更好的哲学。他所有的基于标准的解决方案都带来了额外的复杂性,而没有真正的收益 –

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。