我正在学习 PIMPL 惯用语。它的一个优点是二进制兼容性。我想知道二进制兼容性的优点是什么。谢谢!
(注:该段内容已经是中文,无需翻译)我正在学习 PIMPL 惯用语。它的一个优点是二进制兼容性。我想知道二进制兼容性的优点是什么。谢谢!
(注:该段内容已经是中文,无需翻译)程序使用库。
用户升级库。升级会改变库的二进制接口中的某些内容。
程序现在无法工作,除非重新编译,因为它是基于旧的二进制接口构建的。
v1.0
让我们考虑一下 libMagic
库 v1.0 中的以下类
//MagicNumber.h
struct MagicNumber {
MagicNumber();
int get();
int id;
}
//MagicNumber.cpp
int MagicNumber::get() {
return 42;
}
void foo() {
MagicNumber m;
int i = 27;
std::cout << m.get() + i << '\n';
}
libMagic.so
进行编译时,foo
函数将被编译如下。foo:
Allocate 4 bytes space in stack for m
Allocate 4 bytes space in stack for i and write 27 in it
Call MagicNumber::get //This address is resolved on application startup.
... //Rest of processing
v1.0.1
现在,当libMagic发布新版本v1.0.1时,实现方面有以下更改,但头文件没有更改。//MagicNumber.cpp
int MagicNumber::get() {
return call_real_magic_number_fn();
}
v1.1.0 - 二进制不兼容
假设库有另一个更新版本(v1.1.0),以下是更改内容。
//MagicNumber.h
struct MagicNumber {
MagicNumber();
int get();
int id;
int cache; //Note: New member
}
//MagicNumber.cpp
int MagicNumber::get() {
if(cache != 0) return cache;
cache = call_real_magic_number_fn();
return cache;
}
foo
函数将不会为新增成员分配空间。该库已经破坏了二进制兼容性。foo:
Allocate 4 bytes space in stack for m //4 bytes is not enough for m
Allocate 4 bytes space in stack for i and write 27 in it.
Call MagicNumber::get //This address is resolved on application startup.
... //Rest of processing
i=27
写入缓存变量中,MagicNumber::get
将返回27。但任何事情都有可能发生。
libMagic
使用了 PIMPL 模式,那么所有成员变量将属于 MagicNumberImpl
类,其大小不会暴露给应用程序代码。因此,库作者可以在后续版本的库中添加新成员,而不会破坏二进制兼容性。struct MagicNumberImpl;
struct MagicNumber {
MagicNumber();
private:
MagicNumberImpl* impl;
}