【C++11保姆级教程】移动构造函数(move constructor)和移动赋值操作符(move assignment operator)


前言

在C++11标准中引入了移动语义的概念,通过移动构造函数和移动赋值操作符,我们可以更高效地管理对象的资源。本文将以通俗易懂的方式详细解释移动构造函数和移动赋值操作符的概念,并通过生动的比喻帮助读者更好地理解这两个概念。


一、移动构造函数(Move Constructor)

1.1 移动构造函数是什么?

移动构造函数是一个特殊的构造函数,它能够从一个右值引用(rvalue reference)创建新的对象,而无需进行深拷贝(deep copy)。我们可以将移动构造函数比喻成搬家时的快递员。

假设你搬家,有一堆家具需要装进卡车。传统的深拷贝(复制构造函数)就像是你把每一件家具都精心地复制一份,然后放进卡车上。这个过程费时费力,而且你原本的家具还要保留。

但是,如果你找来一位勇敢的快递员(移动构造函数),他们可以直接将你的家具移动到新的屋子里,而不用复制。这样,节省了时间和精力,而且你原本的家具可以顺利放进新的屋子。

在代码中,移动构造函数使用右值引用作为参数,并且我们将原始对象的资源直接转移到新对象中,而不是进行复制。这就如同快递员将家具从旧的房子搬到新的房子中,节省了时间和空间开销。

总的来说:可以理解为快速的拷贝构造函数

1.2 基本格式

在构造函数后面写noexcept

ClassName(ClassName&& other) noexcept
{
    // Move the resources from 'other' to the new object
    // ...
}

1.3 示例代码

#include <iostream>

class MyObject {
private:
    int* data;

public:
    MyObject() : data(nullptr) {
        std::cout << "Default Constructor" << std::endl;
    }

    MyObject(int value) : data(new int(value)) {
        std::cout << "Regular Constructor" << std::endl;
    }

    // 移动构造函数
    MyObject(MyObject&& other)noexcept : data(other.data) {
        other.data = nullptr;
        std::cout << "Move Constructor" << std::endl;
    }

    ~MyObject() {
        delete data;
        std::cout << "Destructor" << std::endl;
    }

    void printData() const {
        if (data != nullptr) {
            std::cout << "Data: " << *data << std::endl;
        } else {
            std::cout << "Data is null" << std::endl;
        }
    }
};

int main() {
    MyObject obj1(10);
    obj1.printData();

    MyObject obj2(std::move(obj1));  // 使用std::move调用移动构造函数
    obj2.printData();
    
    obj1.printData();  // obj1的data现在为null

    return 0;
}

1.4 输出结果

Regular Constructor
Data: 10
Move Constructor
Data: 10
Data is null
Destructor
Destructor

在这里插入图片描述

二、移动赋值操作符(Move Assignment Operator)

2.1 移动赋值操作符是什么?

移动赋值操作符允许我们将一个对象的资源转移到另一个对象上。可以把移动赋值操作符比喻成两个人交换工作岗位。

想象一下,你在一家公司工作,有一天你被调往另外一个部门。传统的方式是,你将自己的工作内容复制一份,再将新工作的内容复制回来,形成了两份一样的工作内容。这样的操作显然很冗余。

然而,通过移动赋值操作符,你可以直接将自己的工作内容交给新的员工,并且接管他们原本的工作,省去了不必要的复制步骤。

在代码中,移动赋值操作符也使用右值引用作为参数。我们将源对象的资源直接转移到目标对象中,同时将源对象恢复到一种可安全销毁或重新赋值的状态。这就如同两个人交换工作岗位,互相拥有对方的资源和责任。

总的来说:可以理解为快速的赋值运算符。(比一般的更快,因为无需深拷贝)

2.2 一般格式

ClassName& operator=(ClassName&& other) noexcept
{
    // Move the resources from 'other' to the current object
    // ...
    return *this;
}

示例代码:

#include <iostream>

class MyObject {
private:
    int* data;

public:
    MyObject() : data(nullptr) {
        std::cout << "Default Constructor" << std::endl;
    }

    MyObject(int value) : data(new int(value)) {
        std::cout << "Regular Constructor" << std::endl;
    }

    // 移动构造函数
    MyObject(MyObject&& other) noexcept : data(other.data) {
        other.data = nullptr;
        std::cout << "Move Constructor" << std::endl;
    }

    // 移动赋值操作符
    MyObject& operator=(MyObject&& other) noexcept {
        if (this != &other) {
            delete data;
            data = other.data;
            other.data = nullptr;
        }
        std::cout << "Move Assignment Operator" << std::endl;
        return *this;
    }

    ~MyObject() {
        delete data;
        std::cout << "Destructor" << std::endl;
    }

    void printData() const {
        if (data != nullptr) {
            std::cout << "Data: " << *data << std::endl;
        } else {
            std::cout << "Data is null" << std::endl;
        }
    }
};

int main() {
    MyObject obj1(10);
    obj1.printData();

    MyObject obj2;
    obj2 = std::move(obj1);  // 使用std::move调用移动赋值操作符
    obj2.printData();

    obj1.printData();  // obj1的data现在为null

    return 0;
}

2.3 输出

Regular Constructor
Data: 10
Default Constructor
Move Assignment Operator
Data: 10
Data is null
Destructor

在这里插入图片描述


总结

当我们需要在C++中处理大量数据或动态分配的对象时,移动构造函数和移动赋值操作符成为了重要的工具。它们是C++11引入的特性,旨在提高程序的性能和效率。
移动构造函数(move constructor)和移动赋值操作符(move assignment operator)的作用是允许将临时对象或资源所有权从一个对象转移给另一个对象,而无需执行深层的数据拷贝和分配新资源。相比复制构造函数和复制赋值操作符,移动操作通常更加高效,因为它只需要重新指定资源的所有权关系,而不需要执行资源的复制或分配。
移动构造函数的语法如下:

类名(类名&amp;&amp; other) noexcept
{
    // 进行资源所有权的转移
}

移动赋值操作符的语法如下:

类名&amp; operator=(类名&amp;&amp; other) noexcept
{
    if (this != &amp;other) {
        // 进行资源所有权的转移
    }
    return *this;
}

在移动构造函数和移动赋值操作符中,我们通过使用右值引用(&&)来标识移动语义,并使用std::move()函数将对象转换为右值。
使用移动构造函数和移动赋值操作符的好处包括:

1.减少不必要的数据拷贝和资源分配,提高程序的性能和效率。
2.在处理大型对象或大量数据时,减少内存的占用和提高程序的响应速度。
3.支持对不可拷贝的对象进行移动操作,使得这些对象也可以被移动和管理。

在使用移动操作时,需要注意以下几点:

4.移动构造函数和移动赋值操作符通常会将被移动对象的资源指针设置为nullptr,以避免资源的重复释放。
5.移动构造函数和移动赋值操作符通常应该具有noexcept规定,表示它们不会抛出异常。
6.移动操作并不会自动删除或释放资源,只是转移资源的所有权关系。移动后的对象需要负责管理和释放资源。移动后的源对象状态通常不可预测,应当谨慎使用。
7.使用移动操作时,对象的移后状态应该仍然是有效且可用的。

总而言之,移动构造函数和移动赋值操作符是C++11引入的重要特性,通过资源所有权的转移而不是数据的拷贝,提高了程序的性能和效率。对于处理大量数据或动态分配的对象,使用移动操作可以显著减少资源的复制和分配,从而提升程序的效率。然而,在使用移动操作时需要注意管理资源的责任,并确保对象的移后状态仍然有效和可用。

  • 14
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
C++中的字符串赋值函数、移动赋值函数和移动构造函数分别是: 1. 字符串赋值函数(Assignment Operator):在C++中,可以使用赋值操作符(=)来将一个字符串赋值给另一个字符串。例如: ```cpp std::string str1 = "Hello"; std::string str2; str2 = str1; // 使用赋值操作符将str1的值赋给str2 ``` 这里,使用赋值操作符将str1的值赋给str2。 2. 移动赋值函数(Move Assignment Operator):移动赋值函数用于在性能上优化对象的赋值过程,通过移动资源而不是进行深拷贝。它使用`&&`来接收右值引用参数。例如: ```cpp class MyString { public: // 移动赋值函数 MyString& operator=(MyString&& other) noexcept { if (this != &other) { // 释放当前对象的资源 delete[] m_data; // 移动other的资源到当前对象 m_data = other.m_data; m_size = other.m_size; // 清空other对象 other.m_data = nullptr; other.m_size = 0; } return *this; } private: char* m_data; size_t m_size; }; ``` 这里,移动赋值函数通过移动`other`对象的资源到当前对象,并清空`other`对象。 3. 移动构造函数(Move Constructor):移动构造函数用于在性能上优化对象的构造过程,通过移动资源而不是进行深拷贝。它使用`&&`来接收右值引用参数。例如: ```cpp class MyString { public: // 移动构造函数 MyString(MyString&& other) noexcept { m_data = other.m_data; m_size = other.m_size; other.m_data = nullptr; other.m_size = 0; } private: char* m_data; size_t m_size; }; ``` 这里,移动构造函数通过移动`other`对象的资源到当前对象,并清空`other`对象。 需要注意的是,移动赋值函数和移动构造函数一般需要保证不抛出异常,因此通常会使用`noexcept`关键字声明它们。另外,移动赋值函数和移动构造函数通常与移动语义相关的类一起使用,如智能指针、容器等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人才程序员

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值