添加move构造函数会破坏二进制兼容性吗

Does adding a move constructor break binary compatibility?

本文关键字:二进制 兼容性 move 构造函数 添加      更新时间:2023-10-16

如果我在库中添加移动构造函数(或移动赋值运算符),我会破坏二进制兼容性吗?这个添加会以任何方式破坏用户的代码吗?

class Foo {
public:
Foo();
Foo(Foo const&);
Foo& operator=(Foo const&);
// new methods:
Foo(Foo&&);
Foo& operator=(Foo&&);
};

在我看来,只要你不添加成员或虚拟函数,就不会对二进制兼容性产生任何影响,因为对象的布局不会改变。

如果一个组件(比如共享库,windows上的.dll或Linux上的.so)使用旧版本的库,那么它将复制对象的所有实例(甚至是右值),而不管它是由使用新库的组件创建的(反之亦然)。

只要使用移动语义来提高性能,并且因此产生的移动对象的行为与复制的对象相同,就应该没有问题。唯一的区别是对内存分配和拷贝(等等)的调用减少,从而提高了性能。如果移动操作用于生成不同的语义(移动的对象与复制的对象不同),那么所有的赌注都是不可能的,但我认为没有人会故意这样做(可能是为了工作安全)。

只要对象的二进制布局不变,我看不出如何引入任何破坏。

它肯定在一个方向上破坏了二进制兼容性:根据新库编译的代码无法与旧库一起使用,因为链接时找不到move构造函数。

另一个方向更为棘手。这通常不是什么大问题,但代码可以通过SFINAE技巧至少观察到新赋值运算符的存在,并且您最终会得到一个程序,其中一些部分认为该运算符存在,而其他部分则不存在。如果同一代码编译两次(在不同的翻译单元中实例化相同的模板),这甚至可能导致ODR冲突。而这些ODR违规可能会再次导致链接时间错误。