C++ 11 中的move赋值运算符

C++ 11 中的move赋值运算符

移动赋值是一种将资源(如内存、文件等)从一个对象转移到另一个对象而不复制它们的方法。

例子:

cpp 复制代码
#include <iostream>
#include <vector>
// for std::move
#include <utility> 

int main() {
    std::vector<int> a = {1, 2, 3, 4};
    std::vector<int> b;
    // move assignment!
    b = std::move(a);  
    // a is now empty
    std::cout << "a.size() = " << a.size() << "\n";
    // b has the data
    std::cout << "b.size() = " << b.size() << "\n";  
}

输出:

bash 复制代码
a.size() = 0
b.size() = 4

移动赋值运算符

这是一个特殊函数,允许一个对象从另一个对象获取资源的所有权,而无需复制。

用户自定义移动赋值运算符

程序员可以自定义移动赋值运算符。

例子:

cpp 复制代码
#include <iostream>
#include <cstring>

class MyString {
    char* data;

public:
    // Constructor
    MyString(const char* str = "") {
        data = new char[strlen(str) + 1];
        strcpy(data, str);
    }

    // User-defined move assignment operator
    MyString& operator=(MyString&& other) {
        std::cout << "Move assignment called\n";

        if (this != &other) {
            // Free old memory
            delete[] data;
            // Steal the pointer
            data = other.data;
            // Set source to null
            other.data = nullptr; 
        }

        return *this;
    }

    // Destructor
    ~MyString() {
        delete[] data;
    }

    void print() const {
        if (data)
            std::cout << data << "\n";
        else
            std::cout << "[empty]\n";
    }
};
int main() {
    MyString a("Hello");
    MyString b("World");

    b = std::move(a);  

    b.print();  
    a.print();  
}

输出:

bash 复制代码
Move assignment called
Hello
[empty]

移动赋值运算符的必要性

  • 提升性能 - 移动赋值运算符通过转移资源而非复制资源来提高速度,尤其对于大型对象而言。

  • 减少内存占用 - 它通过重用现有资源避免在内存中创建不必要的重复项。

  • 高效处理临时对象 - 移动赋值运算符允许对象从临时值中获取数据所有权,而无需进行代价高昂的复制操作。

自己实现字符串move拷贝构造和move赋值运算符重载

示例

cpp 复制代码
#include <iostream>

// - [https://www.youtube.com/@TheCherno](https://www.youtube.com/@TheCherno)

// ## C++基础
// - [lvalues and rvalues in C++](https://www.youtube.com/watch?v=fbYknr-HPYE)
// - [std::move and the Move Assignment Operator in C++](https://www.youtube.com/watch?v=OWNeCTd7yQE)
// - [Move Semantics in C++](https://www.youtube.com/watch?v=ehMg6zvXuMY)
// - [SMART POINTERS in C++ (std::unique_ptr, std::shared_ptr, std::weak_ptr)](https://www.youtube.com/watch?v=UOB7-B2MfwA)
// - [Weak Pointers in C++ (std::weak_ptr)](https://www.youtube.com/watch?v=M0GLQEfplxs)


class MyString
{
    public:
        MyString() = default;
    
        MyString(const char* s)
        {
            std::cout << "Created!" << std::endl;
    
            m_Size = strlen(s);
            m_Data = new char[m_Size];
            memcpy(m_Data, s, m_Size);
        }

    MyString(const MyString& other)
        : m_Size(other.m_Size)
    {
        std::cout << "Copied!" << std::endl;

        m_Data = new char[m_Size];
        memcpy(m_Data, other.m_Data, m_Size);
    }

    MyString(MyString&& other) noexcept
    {
        std::cout << "Moved!" << std::endl;

        m_Data = other.m_Data;
        m_Size = other.m_Size;

        other.m_Data = nullptr;
        other.m_Size = 0;
    }

    MyString& operator=(const MyString& other) noexcept
    {
        std::cout << "Assigned!" << std::endl;
        if (this == &other)
            return *this;

        delete[] m_Data;

        m_Size = other.m_Size;
        m_Data = new char[m_Size];
        memcpy(m_Data, other.m_Data, m_Size);
        
        return *this;
    }

    MyString& operator=(MyString&& other) noexcept
    {
        std::cout << "Move Assigned!" << std::endl;
        if (this == &other)
            return *this;

        delete[] m_Data;

        m_Data = other.m_Data;
        m_Size = other.m_Size;

        other.m_Data = nullptr;
        other.m_Size = 0;

        return *this;
    }

    ~MyString()
    {
        std::cout << "Destroyed!" << std::endl;
        delete[] m_Data;
    }

    void Print() const
    {
        for (unsigned int i = 0; i < m_Size; i++)
            std::cout << m_Data[i];
        std::cout << std::endl;
    }

    private:
        char* m_Data = nullptr;
        unsigned int m_Size = 0;
};

class Entity
{
public:
    Entity(const MyString& name)
        : m_Name(name)
    {
    }

    Entity(MyString&& name)
        : m_Name(std::move(name))
    {
    }
private:
    MyString m_Name;
};

int main()
{
    {
        MyString hello = "Hello World!";
        Entity e1(hello);                  // Copy
        Entity e2(std::move(hello));       // Move
    }

    std::cout << "---------------------" << std::endl;

    MyString apple = "Apple";
    MyString dest;

    std::cout << "Apple: ";
    apple.Print();
    std::cout << "Dest: ";
    dest.Print();

    dest = std::move(apple); // Move Assignment

    std::cout << "Apple: ";
    apple.Print();
    std::cout << "Dest: ";
    dest.Print();


    return 0;
}

输出

bash 复制代码
Created!
Copied!
Moved!
Destroyed!
Destroyed!
Destroyed!
---------------------
Created!
Apple: Apple
Dest: 
Move Assigned!
Apple: 
Dest: Apple
Destroyed!
Destroyed!

参考资料

相关推荐
CodeGL2 分钟前
9、Python基础之IO编程
开发语言·数据库·python
曹牧25 分钟前
SVN:失联项目
开发语言
传奇开心果编程1 小时前
【Rust入门练中学】第9课:集合类型
开发语言·rust·编程语言理论·集合类型·通用编程语言
龙孚信息1 小时前
跨境电商独立站的安全盲区:一次 PHP 核心漏洞的影响评估
开发语言·安全·php
牛牛牌蜡笔小新1 小时前
Java-常用类库
java·开发语言
sunsijia219831 小时前
2026年10月22日 PHP漏洞临时处理
开发语言·php
Aurorar0rua1 小时前
CS50 x 2024 Notes Python - 02
开发语言·python·学习方法
zyseo82 小时前
谷歌SEO 网站迁移 301 映射脚本:旧站 URL 自动匹配新站结构
开发语言·python
cu1432 小时前
细谈IT65631的具体功能与其应用
c++·单片机·嵌入式硬件
清水白石0082 小时前
React Native与Flutter长期维护成本对比
开发语言·数据库