c++ - 构造函数调用返回语句

标签 c++ language-lawyer c++17

考虑以下示例:

class X {
public:
    X() = default;
    X(const X&) = default;
    X(X&&) = delete;
};

X foo() {
    X result;
    return result;
}

int main() {
    foo();
}

Clang 和 GCC 对这个程序是否有效存在分歧。在调用 foo() 期间初始化临时对象时,GCC 尝试调用 move 构造函数,该构造函数已被删除,导致编译错误。即使使用 -fno-elide-constructors,Clang 也能很好地处理这个问题。

谁能解释为什么在这种情况下允许 GCC 调用移动构造函数? result 不是左值吗?

最佳答案

我要引用 C++17 (n4659),因为那里的措辞是最清楚的,但以前的修订版也是这么说的,只是对我来说不太清楚。这里是 [class.copy.elision]/3 ,强调我的:

In the following copy-initialization contexts, a move operation might be used instead of a copy operation:

  • If the expression in a return statement is a (possibly parenthesized) id-expression that names an object with automatic storage duration declared in the body or parameter-declaration-clause of the innermost enclosing function or lambda-expression, or

  • [...]

overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue. If the first overload resolution fails or was not performed, or if the type of the first parameter of the selected constructor is not an rvalue reference to the object's type (possibly cv-qualified), overload resolution is performed again, considering the object as an lvalue. [ Note: This two-stage overload resolution must be performed regardless of whether copy elision will occur. It determines the constructor to be called if elision is not performed, and the selected constructor must be accessible even if the call is elided.  — end note ]

所以这就是为什么事实上 Clang 和 GCC 都会尝试首先调用 move c'tor。行为上的差异是因为 Clang 以不同的方式坚持粗体文本。发生了重载解决方案,找到了一个移动 c'tor,但调用它是不正确的。所以 Clang 再次执行它并找到复制 c'tor。

GCC 刚刚停止,因为在重载解决方案中选择了一个已删除的函数。

我确实相信 Clang 在这里是正确的,如果有其他的话,在精神上。尝试移动返回的值并作为后备进行复制是此优化的预期行为。我觉得 GCC 不应该停止,因为它发现了一个已删除的 move c'tor。如果它是定义删除的默认移动 c'tor,则编译器都不会。该标准意识到 情况下的潜在问题 ([over.match.funcs]/8):

A defaulted move special function ([class.copy]) that is defined as deleted is excluded from the set of candidate functions in all contexts.

关于c++ - 构造函数调用返回语句,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47881013/

相关文章:

c++ - 创建MySQL无限循环

c++ - Bada 的 AppLog 奇怪地破坏了我报告的字符串

c++ - volatile 是否作为优化的编译器障碍

c++ - 模板函数中的参数类型可以推断吗?

c++ - `operator()...`在C++代码中是什么意思?

c++ - Rust 位域和枚举 C++ 风格

c++ - Sfml 碰撞 : when the player hits a square, 他只是停止移动

c++ - 为什么 [intro.execution]/12 认为访问 volatile glvalue 是副作用?

c++ - placement new 如何知道要创建哪个布局?

c++ - 保证复制省略世界中的构造函数实例化