当赋值运算符被明确删除时,是否允许从rvalue赋值?

时间:2016-03-29 17:43:33

标签: c++ c++11 move-semantics move-constructor move-assignment-operator

考虑下面的代码,它在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规范中是否有一些子句允许编译器将赋值初始化转换为复制构造,即使明确删除了类型的赋值运算符?

1 个答案:

答案 0 :(得分:3)

那是因为这不是作业:

S tmp = GetS(); 

它被称为copy-initialization并调用您已明确默认的移动构造函数。

基本上,仅在已存在的对象上调用赋值运算符。 tmp尚不存在,此语句对其进行初始化。因此,您正在调用构造函数。

请注意GetS() 内的内容不会影响tmp的构建规则。 GetS()无论如何都是左值。