模板中的 pimpl-idiom;哪个智能指针?
我通常对 pimpl 使用 boost::scoped_ptr (出于一个原因,因为如果我忘记处理复制构造函数,我不会感到惊讶)
但是使用模板,我不能只将析构函数放在 impl 所在的 cpp 文件中已完全定义,以满足scoped_ptr 析构函数的要求。无论如何它确实有效,但我不确定它是否能保证有效或只是偶然。是否有一些“最佳实践”或标准? scoped_ptr 是不可复制类中 pimpl 的最佳智能指针吗?
template <class T> class C {
public:
C(){}
~C(){}
private:
boost::scoped_ptr<T> pimpl_;
};
I usually use a boost::scoped_ptr for pimpl's (for one reason because then I don't get surprises if I forget to deal with the copy constructor)
With templates however I can't just put the destructor in the cpp file where the impl is fully defined in order to fulfill the requirements of scoped_ptr's destructor. It does work anyway but I'm not sure if its garanteed to work or just by chance. Is there some 'best practice' or standard? Is scoped_ptr the best smart pointer for pimpls in non-copyable classes?
template <class T> class C {
public:
C(){}
~C(){}
private:
boost::scoped_ptr<T> pimpl_;
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
两年后,我更好地了解了这种情况,为了保持堆栈溢出答案的相关性和最新性,我今天将如何回答这个问题。
我原来的问题的前提有些缺陷。使用 pimpl-idiom 的原因是向编译器隐藏实现细节。这是通过不透明指针(指向已声明但未定义的数据类型的指针)存储实现来完成的。这可以大大减少与类交互的其他编译单元所需的标头数量,从而加快编译时间。就我的问题中的模板而言,要求类型 T 在实例化时完全已知,这实际上要求在使用
C
时完全定义 impl 的类型这显然不是经典意义上的 pimpl 习语的例子。通过私有指针保存类数据还有其他原因,例如,它允许轻松实现无抛出移动和交换,并且如果您的类需要实现强大的异常保证,那么它也很好(请参阅复制和交换习惯用法什么是复制和交换习惯用法?)。另一方面,它在每次访问 impl 时添加了一个间接层(通常导致缓存未命中),并在创建和销毁 impl 时添加了堆分配/释放。这些可能会造成严重的性能损失,因此该解决方案不应被视为灵丹妙药。
如果您可以使用 C++11,则应使用 std::unique_ptr 而不是 boost::scoped_ptr。
Two years later I understand the situation much better, in the interest of keeping stack overflow answers relevant and up to date here is how I would answer the question today.
The premise of my original question is somewhat flawed. The reason to use the pimpl-idiom is to hide implementation details from the compiler. This is done by storing the implementation via an opaque pointer (pointer to a declared but not defined data type). This can greatly reduce the amount of headers needed by other compilation units which interact with the class and thus speed up compile time. In the case of the template in my question it is required that the type T be fully known at the point of instantiation which in practice requires the the impl's type be fully defined wherever
C<ImplType>
is used making this clearly not an example of the pimpl-idiom in the classic sense of the term.There are other reasons to hold a classes data via a private pointer, for example it allows for easy implementation of no-throw move and swap and is also good if your class needs to fulfill a strong exception guarantee (see copy and swap idiom What is the copy-and-swap idiom?). On the other hand it adds a layer of indirection (often resulting in a cache miss) on every access to the impl and a heap allocation/deallocation upon creation and destruction of the impl. These can be substantial performance penalties, therefore this solution should not be considered a silver bullet.
If you can use C++11 then std::unique_ptr should be used instead of boost::scoped_ptr.
boost::shared_ptr
不需要除 at 之外的完整定义实例化点——在构造函数中,在 a 的情况下
粉刺。
boost::shared_ptr
不适合pimpl习惯用法,然而,因为它给出了非常意想不到的语义(参考语义
用于转让或复制);如果你真的想要增加复杂性
智能指针,
boost::scoped_ptr
会更合适(但它在其析构函数所在的位置确实需要完整的定义
实例化)。
对于模板,使用 pimpl 习惯用法是没有意义的
标题中的实现细节。在没有
导出
的情况下,必须包含类模板的所有实现细节
到处都使用模板,所以 pimpl 背后的动机
成语不再存在。
boost::shared_ptr
doesn't require a complete definition other than atthe point of instantiation—in the constructor, in the case of a
pimpl.
boost::shared_ptr
is not appropriate for the pimpl idiom,however, since it gives very unexpected semantics (reference semantics
for assignment or copy); if you really want the added complexity of a
smart pointer,
boost::scoped_ptr
would be more appropirate (but itdoes require a full definition at the point its destructor is
instantiated).
With regards to templates, it makes no sense to use the pimpl idiom for
the implementation details from the header. In the absense of
export
,all of the implementation details of a class template must be included
everywhere the template is used, so the motivation behind the pimpl
idiom ceases to exist.
碰巧赫伯·萨特在很长一段时间后又开始写他的《GotWs》。第一批新的内容之一与“编译防火墙”有关。
您可能想看一下:
GotW #100:编译防火墙(难度:6/10)
和
GotW #101:编译防火墙,第 2 部分(难度:8/10)
It just happens that Herb Sutter started to write his GotWs again after a long time. One of the first new ones are related to "Compilation Firewalls".
You might want to take a look at:
GotW #100: Compilation Firewalls (Difficulty: 6/10)
and
GotW #101: Compilation Firewalls, Part 2 (Difficulty: 8/10)