PIMPL 成语真的在实践中使用吗?
我正在阅读 Herb Sutter 的 Exceptional C++" 一书,在这本书中我了解了 PIMPL 习语.基本上,这个想法是为 class
的 private
对象创建一个结构,并动态分配它们以减少编译时间(并隐藏以更好的方式私有实现).
I am reading the book "Exceptional C++" by Herb Sutter, and in that book I have learned about the PIMPL idiom. Basically, the idea is to create a structure for the private
objects of a class
and dynamically allocate them to decrease the compilation time (and also hide the private implementations in a better manner).
例如:
class X
{
private:
C c;
D d;
} ;
可以改为:
class X
{
private:
struct XImpl;
XImpl* pImpl;
};
并且,在 .cpp 文件中,定义:
and, in the .cpp file, the definition:
struct X::XImpl
{
C c;
D d;
};
这看起来很有趣,但我以前从未见过这种方法,无论是在我工作过的公司中,还是在我见过源代码的开源项目中.所以,我想知道这个技术真的在实践中使用过吗?
This seems pretty interesting, but I have never seen this kind of approach before, neither in the companies I have worked, nor in open source projects that I've seen the source code. So, I am wondering it this technique is really used in practice?
我应该到处使用它还是谨慎使用它?是否推荐在嵌入式系统中使用这种技术(性能非常重要)?
Should I use it everywhere, or with caution? And is this technique recommended to be used in embedded systems (where the performance is very important)?
推荐答案
所以,我想知道这种技术真的用于实践吗?我应该在任何地方使用它,还是谨慎使用?
So, I am wondering it this technique is really used in practice? Should I use it everywhere, or with caution?
当然是用了.我在我的项目中使用它,几乎在每个课程中.
Of course it is used. I use it in my project, in almost every class.
在开发库时,您可以向 XImpl
添加/修改字段,而不会破坏与客户端的二进制兼容性(这意味着崩溃!).由于向 Ximpl
类添加新字段时 X
类的二进制布局不会改变,因此在次要版本更新中向库添加新功能是安全的.
When you're developing a library, you can add/modify fields to XImpl
without breaking the binary compatibility with your client (which would mean crashes!). Since the binary layout of X
class doesn't change when you add new fields to Ximpl
class, it is safe to add new functionality to the library in minor versions updates.
当然,您也可以在不破坏二进制兼容性的情况下向 X
/XImpl
添加新的公共/私有非虚拟方法,但这与标准头文件相当/实现技术.
Of course, you can also add new public/private non-virtual methods to X
/XImpl
without breaking the binary compatibility, but that's on par with the standard header/implementation technique.
如果您正在开发一个库,尤其是专有库,最好不要透露使用了哪些其他库/实现技术来实现您的库的公共接口.要么是因为知识产权问题,要么是因为您认为用户可能会倾向于对实现进行危险的假设,或者只是通过使用可怕的转换技巧来破坏封装.PIMPL 解决/减轻了这个问题.
If you're developing a library, especially a proprietary one, it might be desirable not to disclose what other libraries / implementation techniques were used to implement the public interface of your library. Either because of Intellectual Property issues, or because you believe that users might be tempted to take dangerous assumptions about the implementation or just break the encapsulation by using terrible casting tricks. PIMPL solves/mitigates that.
编译时间减少,因为当您向XImpl
类添加/删除字段和/或方法时,只需要重建X
的源(实现)文件(这映射到在标准技术中添加私有字段/方法).在实践中,这是一个常见的操作.
Compilation time is decreased, since only the source (implementation) file of X
needs to be rebuilt when you add/remove fields and/or methods to the XImpl
class (which maps to adding private fields/methods in the standard technique). In practice, it's a common operation.
使用标准的头/实现技术(没有 PIMPL),当你向 X
添加一个新字段时,每一个分配了 X
的客户端(在堆栈上,或者on heap) 需要重新编译,因为它必须调整分配的大小.好吧,每个从未分配过 X 的客户端都需要重新编译,但这只是开销(客户端的结果代码将相同).
With the standard header/implementation technique (without PIMPL), when you add a new field to X
, every client that ever allocates X
(either on stack, or on heap) needs to be recompiled, because it must adjust the size of the allocation. Well, every client that doesn't ever allocate X also need to be recompiled, but it's just overhead (the resulting code on the client side will be the same).
更重要的是,即使在将私有方法 X::foo()
添加到 XClient1.cpp
时,也需要重新编译标准头/实现分离 XClient1.cpp
code>X 和 Xh
发生了变化,即使 XClient1.cpp
由于封装原因不可能调用此方法!像上面一样,它是纯粹的开销,并且与现实生活中的 C++ 构建系统的工作方式有关.
What is more, with the standard header/implementation separation XClient1.cpp
needs to be recompiled even when a private method X::foo()
was added to X
and X.h
changed, even though XClient1.cpp
can't possibly call this method for encapsulation reasons! Like above, it's pure overhead and is related with how real-life C++ build systems work.
当然,当您只是修改方法的实现时不需要重新编译(因为您不接触标头),但这与标准标头/实现技术相当.
Of course, recompilation is not needed when you just modify the implementation of the methods (because you don't touch the header), but that's on par with the standard header/implementation technique.
是否建议在嵌入式系统中使用这种技术(性能非常重要)?
Is this technique recommended to be used in embedded systems (where the performance is very important)?
这取决于你的目标有多强大.然而,这个问题的唯一答案是:衡量和评估您的所得和损失.此外,请注意,如果您不发布旨在供客户在嵌入式系统中使用的库,则只有编译时间优势适用!
That depends on how powerful your target is. However the only answer to this question is: measure and evaluate what you gain and lose. Also, take into consideration that if you're not publishing a library meant to be used in embedded systems by your clients, only the compilation time advantage applies!
相关文章