代码之家  ›  专栏  ›  技术社区  ›  Phil Miller

“保证拷贝删除”(P0135,C++1z)是否可能需要ABI中断?

  •  17
  • Phil Miller  · 技术社区  · 9 年前

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

    2016年6月,在芬兰欧鲁举行的会议上,上述“保证拷贝删除”提案被投票纳入C++工作文件,随后被投票作为委员会草案出版。希望这将导致明年作为C++17标准发布。

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

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

    我在考虑像初始化这样的事情,在创建对象时可以内联,但在跨越编译单元边界时则不会复制。

    1 回复  |  直到 9 年前
        1
  •  12
  •   Nicol Bolas    8 年前

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

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

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

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

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

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

    如果调用者希望在以后的操作中使用返回值内存,那么ABI就可以了。如果被调用者希望将数据直接初始化到返回值内存中,而不是复制它,ABI不会注意到。

    ABI定义了接口;如何使用该接口取决于您。

    例如,考虑 Itanium ABI on return values 它允许类类型存储在寄存器中,但 只有 如果它们有微不足道的复制/移动构造函数。否则,无论其内容如何,它们都必须在调用函数提供的内存中构造。如果类是普通的可复制类,那么您就无法区分省略和非省略。

    ABI对该特性造成问题的唯一方式是,ABI是否任意决定返回值(以及参数)的存储位置,它们之间是否相互关联。也就是说,ABI强制调用者将对象放在堆栈上相对于参数的特定位置。

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