C++ 从右值删除移动构造函数并构造对象

C++ 从右值删除移动构造函数并构造对象,c++,c++11,move,move-semantics,C++,C++11,Move,Move Semantics,我试图理解“有效的现代C++”中关于特殊成员函数生成的第17项,所以我尝试了一些示例,并试图对一些行为进行推理。书中说: …当我提到移动操作移动构造或移动分配数据成员或基类时,不能保证移动将实际发生。“Memberwise移动”实际上更像Memberwise移动请求,因为未启用移动的类型(即,不提供移动操作的特殊支持,例如,大多数C++98遗留类)将通过其复制操作“移动”。 ... 此外,不会为任何显式声明复制操作的类生成移动操作 如果我显式删除move构造函数,下面的代码会出错,但如果我不删除

我试图理解“有效的现代C++”中关于特殊成员函数生成的第17项,所以我尝试了一些示例,并试图对一些行为进行推理。书中说:

…当我提到移动操作移动构造或移动分配数据成员或基类时,不能保证移动将实际发生。“Memberwise移动”实际上更像Memberwise移动请求,因为未启用移动的类型(即,不提供移动操作的特殊支持,例如,大多数C++98遗留类)将通过其复制操作“移动”。 ... 此外,不会为任何显式声明复制操作的类生成移动操作

如果我显式删除move构造函数,下面的代码会出错,但如果我不删除,则对象“s1”会在没有任何错误的情况下得到copy构造。这里有一个指向相同代码的魔杖盒链接:。我想我不明白删除移动构造函数和不定义构造函数之间的区别

#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();
}
#包括
结构
{
S()=默认值;
S(常数S&){

std::cout删除一个特殊的成员函数与不声明它是不同的。这与声明它然后在使用它时强制编译错误是一样的

因此,删除移动向量没有太大的好处……除非您出于某种原因也删除了复制向量,但是根本不声明移动向量

这与引用没有多大关系,也就是说,如果您确实声明了一个move-ctor,但没有在其中执行任何“movey-things”,那么最终没有任何有价值的东西真正被移动,这可能与用户的期望相反

我建议您保留未声明的移动ctor。同样,这与正在删除的移动ctor不同。并且不会自动生成一个移动ctor,因为您有一个副本ctor

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

请注意,由于省略,您的程序在这两种情况下都以C++17模式编译

我想我不明白删除移动构造函数和不定义构造函数之间的区别

#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();
}
当你这样做的时候

struct S
{
    S() = default;
    S(const S&) {
        std::cout << "Copying" << std::endl;
    }
};
当您移动类型为
S
的对象时,重载解析会查找
S(常数S&)
S(S&&)
,但它会选择
S(S&&)
,因为它是更好的匹配对象。然后它会看到它被删除,并且您会得到一个错误


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

引用的位实际上表示,如果您不声明移动构造函数,则复制构造函数将由于您提到的原因,我在链接的示例中禁用了复制省略,并使用c++11进行编译。@MikeSweeney但“不要声明移动构造函数”和“将移动构造函数声明为已删除”是两件事:)