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!

参考资料

相关推荐
jf加菲猫2 小时前
第2章 Hello World
开发语言·c++·qt·ui
yolo_guo2 小时前
opencv 学习: QA_01 什么是图像锐化
linux·c++·opencv·计算机视觉
_OP_CHEN2 小时前
算法基础篇:(六)基础算法之双指针 —— 从暴力到高效的优化艺术
c++·算法·acm·优化算法·双指针·oj题·算法蓝桥杯
todoitbo3 小时前
Rust新手第一课:Mac环境搭建踩坑记录
开发语言·macos·rust
laplace01233 小时前
PyQt5 + Qt Designer配置指令
开发语言·qt
nvd113 小时前
Python 迭代器 (Iterator) vs. 生成器 (Generator)
开发语言·python
oioihoii3 小时前
C++中有双向映射数据结构吗?Key和Value能否双向查找?
数据结构·c++·算法
HalvmånEver3 小时前
Linux:基础开发工具(三)
linux·运维·服务器·开发语言·学习·gcc/g++