std::move

2022-11-19  本文已影响0人  arkliu

移动语义

如果一个对象中有堆区资源,需要编写拷贝构造函数和赋值函数。

深拷贝把对象中的堆区资源复制了一份,如果源对象(被拷贝的资源)是临时对象,拷贝完就没什么用了,这样会造成没有意义的申请资源和释放动作,如果能够直接使用源对象拥有的资源, 可以节省申请和释放时间,c++11新增的移动语义能够做到这一点。

移动构造函数语法

类名(类名&& 源对象) {.....}

移动赋值函数语法

类名& operator=类名&& 源对象) {.....}

实现类的移动构造和移动赋值函数

#include <iostream>
#include <memory>
#include<string>
#include <cstring>
using namespace std;

class AA {
    public:
        int * m_a = nullptr; // 指向堆区资源的指针

        AA()=default;  // 启用默认构造函数

        void alloc() {
            m_a = new int(); // 分配内存
            memset(m_a, 0, sizeof(int)); // 初始化已分配的内存
        }

        AA(const AA &ra) { //拷贝构造函数
            cout << "调用了拷贝构造函数"<<endl;
            if (m_a == nullptr) alloc();
            memcpy(this->m_a, ra.m_a, sizeof(int)); //把数据从源对象拷贝过来
        }

        AA(AA&& ra) { //移动构造函数, 参数是右值引用
            cout << "调用了移动构造函数"<<endl;
            if (m_a != nullptr) delete m_a;  // 如果已经分配内存,先释放掉
            m_a = ra.m_a;      // 把资源从源对象中转移过来
            ra.m_a = nullptr;  //把源对象中的指针置空
        }

        AA& operator=(const AA& ra) { // 赋值函数
            cout << "调用了赋值函数"<<endl;
            if (this == &ra) return *this;
            if (m_a == nullptr) alloc();
            memcpy(this->m_a, ra.m_a, sizeof(int)); //把数据从源对象拷贝过来
            return *this;
        }

        // 移动赋值函数
        AA& operator=(AA&& ra) { 
            cout << "调用了移动赋值函数"<<endl;
            if (this == &ra) return *this;
            if (m_a != nullptr) delete m_a;  // 如果已经分配内存,先释放掉
            m_a = ra.m_a;      // 把资源从源对象中转移过来
            ra.m_a = nullptr;  //把源对象中的指针置空
            return *this;
        }

        ~AA() {
            if (m_a != nullptr)
            {
                delete m_a;
                m_a = nullptr;
            }
            
        }

};

int main() {
    // 如果形参是左值 就调用拷贝构造函数,如果形参是右值,就调用移动构造函数
    AA a1;  // 创建对象a1
    a1.alloc(); // 分配堆区资源
    *(a1.m_a) = 10;  //给堆区内存赋值
    cout << "a1.m_a=" << *a1.m_a << endl;

    AA a2 = a1; // 将调用拷贝构造函数
    cout << "a2.m_a=" << *a2.m_a << endl;

    AA a3;
    a3 = a1; // 将调用赋值构造函数
    cout << "a3.m_a=" << *a3.m_a << endl;

    cout << "----------------" << endl;

    // 返回aa类对象的lambda函数
    auto f =[]() {
        AA aa;
        aa.alloc();
        *(aa.m_a) = 55; 
        return aa;
    };
    AA a4 = f(); // lambda函数返回的临时对象是右值,将调用移动构造函数
    cout << "a4.m_a=" << *a4.m_a << endl;

    AA a5; 
    a5 = f(); // lambda函数返回的临时对象是右值,将调用移动赋值函数
    cout << "a5.m_a=" << *a5.m_a << endl;
    return 0;
}
int main() {
    // 如果形参是左值 就调用拷贝构造函数,如果形参是右值,就调用移动构造函数
    AA a1;  // 创建对象a1
    a1.alloc(); // 分配堆区资源
    *(a1.m_a) = 10;  //给堆区内存赋值
    cout << "a1.m_a=" << *a1.m_a << endl;

    AA a2 = move(a1); // move后,a1左值被转义为右值,将调用移动构造函数
    cout << "a2.m_a=" << *a2.m_a << endl;

    AA a3;
    a3 = move(a1); // move后,a1左值被转义为右值,,将调用移动赋值函数
    cout << "a3.m_a=" << *a3.m_a << endl;
    return 0;
}
image.png
上一篇下一篇

猜你喜欢

热点阅读