考虑下面的代码,它在Clang,GCC和VS 2015(online example)下编译:
#include <utility>
class S
{
public:
S(int x) : i(x) { }
~S() { }
S(S&&) = default;
S(const S& ) = delete;
S& operator=(S&&) = delete;
S& operator=(const S&) = delete;
private:
int i;
};
S GetS()
{
// This is a contrived example with details elided. Assume
// there's a reason in the actual use case for returning via
// std::move.
return std::move( S(999) );
}
int main()
{
S tmp = GetS(); // <-- Assignment allowed even though assignment operator is deleted?
return 1;
}
我不清楚为什么这行
S tmp = GetS();
编译,执行移动构造函数而不是移动赋值运算符。
我知道RVO允许构造和赋值被省略作为优化,但我的理解是,如果在代码中明确使用该运算符,显式删除运算符应该导致编译失败。
C ++ 11规范中是否有一些子句允许编译器将赋值初始化转换为复制构造,即使明确删除了类型的赋值运算符?
答案 0 :(得分:3)
那是因为这不是作业:
S tmp = GetS();
它被称为copy-initialization并调用您已明确默认的移动构造函数。
基本上,仅在已存在的对象上调用赋值运算符。 tmp
尚不存在,此语句对其进行初始化。因此,您正在调用构造函数。
请注意GetS()
中 内的内容不会影响tmp
的构建规则。 GetS()
无论如何都是左值。