std::move

作者: arkliu | 来源:发表于2022-11-19 12:22 被阅读0次

移动语义

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

深拷贝把对象中的堆区资源复制了一份,如果源对象(被拷贝的资源)是临时对象,拷贝完就没什么用了,这样会造成没有意义的申请资源和释放动作,如果能够直接使用源对象拥有的资源, 可以节省申请和释放时间,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;
}
  • 对于一个左值,会调用拷贝构造函数,但是有些左值是局部变量,声明周期也很短,c++11提供了一个std::move()方法来将左值转义为右值,从而方便使用移动语义。
    其实就是告诉编译器\color{red}{虽然我是一个左值,但不要对我调用拷贝构造函数,而是要使用移动构造函数}

  • 如果没有提供移动构造/赋值函数, 只提供了拷贝构造/赋值函数,编译器找不到移动构造/赋值函数,就去寻找拷贝构造/赋值函数

  • c++11 中的所有容器,都实现了移动语义,避免对含有资源的对象,发生无谓的拷贝。

  • 移动语义,对拥有资源(内存,文件句柄) 的对象有用,如果是基本类型,使用移动语义没有意义。

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

相关文章

  • Tips of C++11 std::move与完美转发std:

    C++11 std::move 和 std::forward 用法: 当知道类型时, 用 std::move得到一...

  • std::move()

    在隆冬,我终于直到,我身上有一个不可战胜的夏天。 ——阿尔贝·加缪 今天提交了一次代码,短短一百多行里,被各...

  • std::move

    std::move函数可以以非常简单的方式将左值引用转换为右值引用。通过std::move,可以避免不必要的拷贝操...

  • std::move

    首先需要了解一下c++的值的类型 c++ 值的类型 1. lvalue(左值) 2. prvalue(纯右值) 3...

  • std::move

    班级类包含一个构造方法,传入一个包含许多学生的vector: 这样有个不好的地方是:每次创建班级对象时都需要将st...

  • C++ Move Semantics

    Rvalue references and std::move[https://r859981c931022xju...

  • std::forward和std::move源码分析

    原文:https://blog.csdn.net/kupepoem/article/details/1199480...

  • C++11中std::move、std::forward、左右值

    C++11中std::move、std::forward、左右值引用、移动构造函数的测试 关于C++11新特性之s...

  • 智能指针

    std::unique_ptr<> 初始化:直接初始化、右值赋值、std::move作为函数返回值作为函数形参

  • 一文看懂 C++11 的 右值引用、std::move 和 st

    右值引用、std::move 和 std::forward 是 C++11 中的最重大语言新特性之一。就算我们不主...

网友评论

      本文标题:std::move

      本文链接:https://www.haomeiwen.com/subject/raqetdtx.html