简体   繁体   English

在没有移动构造函数或移动赋值的情况下调用 std::move

[英]Calling std::move without move constructor or move assignment

We know that std::move does not actually move anything .我们知道 std::move实际上并没有移动任何东西 It just cast an lvalue reference (&) to rvalue reference (&&).它只是将左值引用 (&) 转换为右值引用 (&&)。

Then how in the following example, the copy constructor is called?那么在下面的例子中是如何调用复制构造函数的呢? If there is not move constructor, how does constructing an object that is using std::move() falls back on copy constructor?如果没有移动构造函数,构造一个使用 std::move() 的对象如何回退到复制构造函数? Exactly how does this binding for variable b happen?变量b这种绑定究竟是如何发生的?

struct Test {
  // Default constructor
  Test() {
    std::cout << "Constructor is called." << std::endl;
    mValue = 0;
  }
  
  // Copy constructor
  Test(const Test& rhs) {
    std::cout << "Copy Constructor is called." << std::endl;
    mName = rhs.mName;
    mValue = rhs.mValue;
  }
    
  std::string mName;
  int mValue;
};

int main() {
  Test a;
  Test b = std::move(a);
  return 0;
}

Output:输出:

Constructor is called.
Copy Constructor is called.

Let's reason by analogy.让我们通过类比来推理。 Think about this code:想想这段代码:

void doSomething(const int& x) {
    std::cout << "You like " << x << "? That's my favorite number!" << std::endl;
}

int main() {
    doSomething(137); // <-- Here
}

Now, focus on the call in main .现在,专注于main的调用。 This code compiles and runs just fine, but there's something a bit weird about it.这段代码编译并运行得很好,但它有一些奇怪的地方。 Notice that doSomething takes in a const int& .请注意, doSomething接受一个const int& That means it takes in a reference to an int , and references (normally) only bind to lvalues.这意味着它接受对int引用,并且引用(通常)仅绑定到左值。 But the argument here, 137, is an rvalue.但是这里的参数 137 是一个右值。 What gives?是什么赋予了?

The reason this works is that the C++ language specifically allows for const lvalue references to bind to rvalues, even though regular lvalue references can't.这样做的原因是 C++ 语言特别允许const左值引用绑定到右值,即使常规左值引用不能。 For example:例如:

const int& totallyLegal = 137; // Yep, that's fine!
int& whoaNotCoolMan     = 42;  // Compile error!

There are a couple of reasons why you can do this.您可以这样做的原因有几个。 If you have a const lvalue reference, you've promised that you're allowed to look at the referenced object, but you can't modify it.如果您有一个const左值引用,则您已承诺允许您查看被引用的对象,但您不能修改它。 Therefore, it's safe to bind the lvalue reference to an rvalue, since you wouldn't then have a way to take a "pure value" and assign it something.因此,将左值引用绑定到右值是安全的,因为这样您就无法获取“纯值”并为其分配一些东西。 And historically, pre-C++11, when rvalue references didn't exist, this made it possible to write functions that would say "please pass this argument to me in a way that doesn't involve making copies" by using a const lvalue reference.从历史上看,在 C++11 之前,当右值引用不存在时,这使得编写函数成为可能,通过使用const “请以不涉及制作副本的方式将此参数传递给我”左值参考。

Now that we have lvalue references, this rule introduces some points of confusion that weren't previously there.现在我们有了左值引用,这条规则引入了一些以前没有的混淆点。 In particular, a const T& can bind to the result of any expression of type T , even if it's a T& or a T&& .特别是, const T&可以绑定到任何类型T表达式的结果,即使它是T&T&& That's why the copy constructor is selected in your case.这就是为什么在您的情况下选择复制构造函数的原因。

There is one further nuance here, though.不过,这里还有一个细微差别。 The same way that the C++ compiler will automatically define a default constructor, copy constructor, and assignment operator for a class provided that you don't do so yourself, the C++ compiler can automatically define a move constructor as well.与 C++ 编译器自动为类定义默认构造函数、复制构造函数和赋值运算符的方式相同,前提是您自己不这样做,C++ 编译器也可以自动定义移动构造函数。 However, there's a rule saying that if a type has a user-defined copy constructor, then the compiler won't generate a move constructor for you.但是,有一条规则说,如果类型具有用户定义的复制构造函数,则编译器不会为您生成移动构造函数。 So the full answer to your question is "the existence of your copy constructor means that no move constructor is defined, and since the copy constructor takes in a const lvalue reference it'll bind to rvalues as well as lvalues."所以你的问题的完整答案是“你的复制构造函数的存在意味着没有定义移动构造函数,并且由于复制构造函数接受一个const左值引用,它会绑定到右值和左值。”

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM