所以,我想知道这种技术在实践中是否真的被使用?我应该到处使用它还是要谨慎使用?
当然会使用。我在我的项目中几乎每个类中都使用它。
PIMPL技巧的原因:
二进制兼容性
当你开发一个库时,可以向XImpl添加/修改字段而不会破坏与客户端的二进制兼容性(这意味着崩溃!)。由于在向Ximpl类添加新字段时,X类的二进制布局不会改变,因此在库的次要版本更新中添加新功能是安全的。
当然,您也可以向X / XImpl添加新的公共/私有非虚拟方法,而不会破坏二进制兼容性,但这与标准头文件/实现技术相当。
数据隐藏
如果您正在开发一个库,特别是专有库,可能不希望披露用于实现库的公共接口的其他库/实现技术。要么是因为知识产权问题,要么是因为您认为用户可能会对实现做出危险的假设或仅通过使用可怕的转换技巧来打破封装。 PIMPL解决/缓解了这个问题。
编译时间
编译时间减少了,因为只有需要重建X的源(实现)文件时,才需要添加/删除字段和/或方法到XImpl类(这映射到标准技术中的添加私有字段/方法)。在实践中,这是常见的操作。
使用标准的头文件/实现技术(没有PIMPL),当您向X添加新字段时,每个分配X的客户端(无论是在堆栈上还是在堆上)都需要重新编译,因为它必须调整分配的大小。好吧,永远不会分配X的每个客户端也需要重新编译,但这只是开销(客户端代码的结果将相同)。此外,使用标准的头文件/实现分离技术后,即使为了封装原因添加了一个私有方法X::foo()并更改了X.h,XClient1.cpp也需要重新编译,尽管XClient1.cpp不可能调用此方法!与上述情况类似,这纯粹是开销,并与实际的C ++构建系统的工作方式有关。
当然,如果您只修改方法的实现(因为您没有触及头文件),则无需重新编译。但这与标准的头文件/实现技术相当。
在嵌入式系统中(性能非常重要),是否建议使用此技术?
那取决于您的目标设备有多强大。然而,对于这个问题唯一的答案是:衡量和评估您的收益和损失。此外,请注意,如果您不是发布供客户在嵌入式系统中使用的库,则仅适用于编译时间优势!
const unique_ptr<XImpl>
而不是XImpl*
来实现pimpl。 - Neil G