复制省略和普通可复制类型

Copy elision and trivially copyable types

从标准6.7.7(临时对象)可以看出:

When an object of class type X is passed to or returned from a function, if X has at least one eligible copy or move constructor ([special]), each such constructor is trivial, and the destructor of X is either trivial or deleted, implementations are permitted to create a temporary object to hold the function parameter or result object. The temporary object is constructed from the function argument or return value, respectively, and the function's parameter or return object is initialized as if by using the eligible trivial constructor to copy the temporary (even if that constructor is inaccessible or would not be selected by overload resolution to perform a copy or move of the object). [Note 4: This latitude is granted to allow objects of class type to be passed to or returned from functions in registers. — end note]

这是否意味着对于平凡可复制的类型,复制省略不是强制性的?我在这里的理解是,如果我们声明一个像 ~Object() {} 这样的析构函数而不是不声明任何东西(因此析构函数将由编译器生成)或默认的析构函数,该对象将变得不可平凡构造,因此,副本必须执行省略(在我们尊重众所周知的复制省略发生条件的情况下)。

Does it mean that copy elision is not mandatory with trivially copyable types?

原则上,是的,但您引用的部分的目标不是免除 POD 类型的复制省略,而是绕过 ABI 对如何在函数调用中传递对象的限制。它允许通过寄存器传递 POD 对象。鉴于 C++ 抽象机对物理机及其寄存器和调用约定一无所知,这是标准可以做的最好的事情。

保证复制省略是贯穿整个标准的多项更改的结果,其中包括延迟的纯右值实现。详情参考原提案p0135r1.

通过这些更改,可以(并且需要)在不涉及临时对象的情况下初始化对象 ([dcl.init.general]/15.6.1):

— Otherwise, if the destination type is a (possibly cv-qualified) class type:

  • If the initializer expression is a prvalue and the cv-unqualified version of the source type is the same class as the class of the destination, the initializer expression is used to initialize the destination object.