Will'保证复制Elision' (P0135,C ++ 1z)可能需要ABI破损?

时间:2016-06-26 19:43:31

标签: c++ language-lawyer abi c++17 copy-elision

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0135r0.html

上述“保证副本删除”的提议'在2016年6月在芬兰奥卢举行的会议上被选入C ++工作文件,然后被选为委员会草案的出版物。希望明年能够成为C ++ 17标准的出版物。

该提案澄清了涉及临时对象的各种值类别,以在某些用例中强制执行复制构造函数调用。

我的问题是"这个新要求可能会破坏以前可能没有在这些情况下完成复制的编译器的ABI兼容性,或者以不兼容的方式实现它新要求?"

我正在思考像初始化这样的事情,当创建一个对象时可以内联,而不是在跨越编译单元边界时。

1 个答案:

答案 0 :(得分:11)

调用函数时,函数必须返回一个值。该值需要内存才能存在,但返回值需要超出函数本身。 ABI定义了这一切是如何工作的。一般来说,这是由调用者提供一个大小/对齐的内存来为函数返回值。

因此,如果函数计算一个值并返回它,它必须(理论上)将该计算值复制到返回值存储器中。当调用者检索它时,它必须(理论上)将该返回值内存复制到其他堆栈对象中以供以后使用。

非保证副本省略说这些副本都不是必需的。在返回函数方面,允许编译器在生成该值时在内部简单地使用返回值内存,因此return语句不必复制任何内容。在接收方,如果内存将用于初始化堆栈对象,则不必复制到该内存中。

保证副本省略说如果接收方正在初始化相同类型的对象,则接收方将不会考虑该对象是否具有复制/移动构造函数。因此,调用类似auto t = Func();的函数的代码不会将其视为t中的潜在复制操作。处理该代码的编译器将使用Func的堆栈空间中的返回值内存调用t

在被调用者方面,如果直接返回prvalue,则不需要存在复制/移动构造函数。被调用者将直接在返回值存储器中构造prvalue。

这就是事情:ABI并不关心这些。所有ABI关心的都是低级记忆。也就是说,只要调用者传递适当大小和对齐的返回值内存,并且被调用者正在用适当类型的对象初始化该内存...... ABI 不关心

如果调用者想要将该返回值存储器用于以后的操作,那对ABI来说没问题。如果被调用者想要将数据直接初始化到返回值存储器而不是复制它,ABI将不会注意到。

ABI定义了接口;你使用该界面做什么取决于你。

例如,考虑Itanium ABI on return values。它允许类类型存储在寄存器中,但如果它们具有普通的复制/移动构造函数,则仅 。否则,无论其内容如何,​​它们都必须在调用函数提供的内存中构造。如果这个班级很容易被复制,那么你就无法区分省略和非省略。

ABI可能对此功能造成问题的唯一方法是ABI任意决定相对于彼此存储返回值(可能是参数)的位置。也就是说,ABI强制调用者将对象放在相对于参数的特定位置的堆栈上。

这样的ABI会存在吗?我没有特别的知识可以说它不能。可以?我很怀疑它,因为这样的ABI一般会让elision变得非常困难。