C++中的移动构造函数和拷贝构造函数的区别

发布时间 2023-03-25 06:14:46作者: Dijkstra·Liu

拷贝构造函数

拷贝构造函数用于从一个已存在的对象创建一个新的对象,即复制构造函数。它通常有一个类对象作为参数,返回一个新的对象,该对象与原始对象具有相同的值。如果一个类没有定义拷贝构造函数,则编译器会生成一个默认的拷贝构造函数,它将逐个复制所有非静态成员。如果一个类具有指针或引用成员,则需要自己编写拷贝构造函数,以确保正确地复制指针或引用所指向的对象。

 

移动构造函数和移动赋值运算符

移动构造函数和移动赋值运算符是 C++11 中引入的新特性,用于从一个临时对象创建一个新对象,以提高效率和减少内存使用。它们采用右值引用的语法,并将临时对象的资源移动到新对象中,而不是复制它们。如果一个类具有指针或其他资源成员,则需要实现移动构造函数和移动赋值运算符,以确保正确地移动这些资源。

 

移动构造函数和拷贝构造函数都是 C++ 中的构造函数,但是它们的功能和用途是不同的。下面是两者的区别:

1. 功能不同

拷贝构造函数用于从一个已存在的对象创建一个新的对象,即复制构造函数。它会复制原始对象的所有成员变量的值,从而创建一个新的、与原始对象相同的对象。

移动构造函数用于从一个右值引用的临时对象创建一个新的对象。它会“窃取”原始对象的资源(例如指针或文件句柄),并将其移动到新对象中,从而避免复制大量数据,提高性能和减少内存使用。

2. 形参类型不同

拷贝构造函数的参数通常是 const 引用类型的对象,例如:

MyClass(const MyClass& other);

 

移动构造函数的参数通常是右值引用类型的对象,例如:

MyClass(MyClass&& other);

3. 调用时机不同

拷贝构造函数通常在以下情况下被调用:

  • 用一个对象初始化另一个对象
  • 传递一个对象作为参数到函数中
  • 从函数中返回一个对象

移动构造函数通常在以下情况下被调用:

  • 从一个临时对象创建一个新对象
  • 将一个临时对象作为参数传递到函数中
  • 从函数中返回一个临时对象

4. 适用范围不同

拷贝构造函数适用于所有类型的对象,包括具有指针和资源的对象。

移动构造函数适用于具有可移动资源的对象,例如指针、文件句柄、unique_ptr 等,但不适用于具有固定位置内存的对象,例如数组、vector 等。

总之,拷贝构造函数和移动构造函数都是重要的构造函数,用于在不同的场合创建新的对象。它们在语法、功能、调用时机和适用范围等方面都有所不同,需要根据实际需要选择使用。

 

下面是一个使用移动构造函数的简单例子:

#include <iostream>
#include <string>

class MyString {
public:
    MyString() : str(nullptr), len(0) {}

    MyString(const char* s) : str(nullptr), len(0) {
        if (s != nullptr) {
            len = strlen(s);
            str = new char[len + 1];
            strcpy(str, s);
        }
    }

    // 拷贝构造函数
    MyString(const MyString& other) : str(nullptr), len(0) {
        if (other.str != nullptr) {
            len = other.len;
            str = new char[len + 1];
            strcpy(str, other.str);
        }
    }

    // 移动构造函数
    MyString(MyString&& other) noexcept {
        str = other.str;
        len = other.len;
        other.str = nullptr;
        other.len = 0;
    }

    ~MyString() {
        if (str != nullptr) {
            delete[] str;
            str = nullptr;
            len = 0;
        }
    }

private:
    char* str;
    size_t len;
};

int main() {
    MyString s1("Hello");  // 调用构造函数
    MyString s2(s1);      // 调用拷贝构造函数
    MyString s3(std::move(s1));  // 调用移动构造函数
    return 0;
}