17

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

2016 年 6 月在芬兰奥卢举行的会议上,上述关于“保证复制省略”的提案被投票纳入 C++ 工作文件,然后被投票作为委员会草案发布。希望这会导致明年作为 C++17 标准发布。

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

我的问题是“这个新要求是否可能会破坏以前在这些情况下可能没有进行复制省略的编译器的 ABI 兼容性,或者以与新要求不兼容的方式实现它?”

我正在考虑诸如初始化之类的事情,当可以内联对象的创建时会省略副本,但在跨越编译单元边界时则不会。

4

1 回答 1

12

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

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

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

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

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

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

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

ABI 定义接口;你用那个界面做什么取决于你。

例如,考虑返回值的 Itanium ABI。它允许将类类型存储在寄存器中,但前提是它们具有简单的复制/移动构造函数。否则,无论它们的内容如何,​​它们都必须在调用函数提供的内存中构造。如果该类是可简单复制的,那么您将无法区分省略和非省略之间的区别。

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

这样的 ABI 会存在吗?我没有特别的知识可以说它不能。可以?我相当怀疑它,因为这样的 ABI 通常会使省略非常困难。

于 2016-06-26T20:19:40.600 回答