C++ std::move 的一些问题

看 SO 上有一个比较奇怪的问题,

问题代码:

ClassX c = std::move(object_c);  // Invokes move constructor

ClassX&& cr = std::move(object_c);
ClassX c = cr;  // Invokes copy constructor

题主的疑问:cr 是右值了,为什么 `ClassX c = cr` 会触发拷贝构造,而不是移动构造

对此的解释:

If it has a name, it's an lvalue. cr is a name, it's an lvalue. 

the code should do ClassX c = std::move(cr);. Keep in mind that std::move does not itself move anything, it only allows a move to occur as-if the variable were an unnamed temporary (such as a return value or result of an expression). It also allows a variable to be bound to an rvalue reference (usually something that is useful for parameter passing). If you find this to be confusing, you are not alone; it is confusing.  

我测试的 demo:

#include <iostream>

class A {
 public:
  A() { std::cout << "Constructors" << std::endl; }

  A(const A& a) { std::cout << "Copy Constructors" << std::endl; }

  A& operator=(const A& a) {
    std::cout << "Assignment Operators" << std::endl;

    return *this;
  }

  A& operator=(const A&& a) {
    std::cout << "Move Assignment Operators" << std::endl;
    return *this;
  }
};

int main() {
  A a;    // Constructors
  A a_5;  // Constructors
  A a_6;  // Constructors

  A&& a_1 = std::move(a);  // 没有提示
  A& a_2 = a;              // 没有提示

  A a_7 = a_1;           // Copy Constructors
  A a_3 = a;             // Copy Constructors
  A a_4(a);              // Copy Constructors
  A a_8 = std::move(a);  // Copy Constructors

  a_6 = a_1;  // Assignment Operators
  a_5 = a;    // Assignment Operators
  a_1 = a_8;  // Assignment Operators

  a_6 = std::move(a_1);  // Move Assignment Operators

  return 0;
}

  

 

std::move

  • std::move 是一个函数模板,用于将一个左值转换为右值引用,从而告诉编译器允许在之后的操作中对该值进行移动语义的操作。
  • 移动语义是 C++11 引入的特性,它允许在不拷贝的情况下将对象的资源(比如动态分配的内存)转移给其他对象,提高了性能
  • std::move 并不会真正移动数据,它只是将对象标记为“可以移动”,使得在后续操作中调用移动构造函数或移动赋值运算符
  • 使用 std::move 的目的是告诉编译器你希望使用移动语义,但要注意,使用之后原来的对象可能处于有效但未定义的状态

移动构造函数和移动赋值运算符写法如下:

class MyClass {
public:
    // 移动构造函数
    MyClass(MyClass&& other) {
        // 将资源从 other 移动到当前对象
        // ...
    }
};

class MyClass {
public:
    // 移动赋值操作符
    MyClass& operator=(MyClass&& other) {
        // 将资源从 other 移动到当前对象
        // ...
        return *this;
    }
};

 

MyClass(MyClass&&) - 移动构造函数:

  • MyClass(MyClass&&) 是一个移动构造函数。它接受一个右值引用作为参数,允许将一个临时对象的资源(如堆上分配的内存)移动到新创建的对象中。
  • 移动构造函数通常用于在创建新对象时避免不必要的资源拷贝,从而提高性能。例如,在 C++11 中,容器在进行元素插入时可以使用移动构造函数来避免额外的拷贝操作。
  • 移动构造函数通常不会修改源对象的状态,而是将源对象的资源所有权转移给新对象。

MyClass& operator=(MyClass&&) - 移动赋值操作符:

  • MyClass& operator=(MyClass&&) 是一个移动赋值操作符。它用于将一个右值引用的对象的资源(如堆上分配的内存)移动到另一个对象中。
  • 移动赋值操作符用于在赋值操作时避免不必要的资源拷贝,从而提高性能。它可以被用于自定义移动赋值,以实现在赋值时的资源转移。

移动构造函数用于创建新对象并从右值引用中获取资源,而移动赋值操作符用于将资源从一个右值引用的对象移动到另一个对象中

posted @ 2023-06-20 11:42  strive-sun  阅读(20)  评论(0编辑  收藏  举报