从右值中删除move构造函数并构造对象

时间:2019-05-21 15:48:09

标签: c++ c++11 move move-semantics

我试图从“ Effective Modern C ++”中了解关于特殊成员函数生成的第17项,因此我尝试了一些示例并试图对某些行为进行推理。书中写着:

  

..当我引用移动操作移动或构造数据成员或基类的移动操作时,并不能保证实际上会发生移动。实际上,“成员移动”更像是成员移动请求,因为未启用移动的类型(即,不提供对移动操作的特殊支持,例如,大多数C ++ 98旧类) ”通过他们的复制操作。   ...   此外,不会为任何明确声明复制操作的类生成移动操作。

如果我显式删除move构造函数,则下面的代码会出错,但是如果我不删除对象“ s1”,则将其复制而没有任何错误。这是指向相同代码的wandbox链接:wandbox link。我想我不了解删除move构造函数与不定义一个构造函数之间的区别。

#include <iostream>

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
   // S(S&&) = delete;
};

S return_lvalue() {
    S ret{};
    return ret;
}

int main() {
    std::cout << "Hello world" << std::endl;
    // Error here if I delete move constructor
    S s1 = return_lvalue();
}

2 个答案:

答案 0 :(得分:3)

  

我想我不了解删除move构造函数和不定义一个构造函数之间的区别。

完成时

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
};

编译器将不会生成move构造函数。如果您尝试移动它,则过载解析将仅找到S(const S&),并且您将获得一个副本。使用

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
    S(S&&) = delete;
};

当您移动类型为S的对象时,重载分辨率会找到S(const S&)S(S&&),但会选择S(S&&),因为这是更好的匹配。然后看到它已被删除,并且出现错误。

您需要记住的是删除的构造函数,请不要从类中删除它们。它声明它们并使它们可用于重载解决方案,并且只有在发生重载解决方案之后,它才会检查是否将其删除。

答案 1 :(得分:0)

删除特殊成员函数与不声明它是不同的。等同于在使用它时声明它并强制编译错误。

这样,删除移动ctor并不会带来很多好处……除非您由于某种原因也删除了复制ctor,但是根本就不用声明移动ctor。

这与报价没有多大关系,也就是说,如果您要做声明了一个举动但没有做任何“搬迁”,那么最终实际上没有任何价值感动,可能与用户的期望相反。

我建议您不要声明移动ctor。同样,这与被删除不一样。而且不会自动生成一个,因为您有一个副本ctor。

在此处查找更多技术信息:

请注意,由于省略,您的程序在C ++ 17模式下都可以编译。