当前位置: 首页 > article >正文

什么是 C++ 中的移动语义?它的作用是什么?右值引用是什么?如何使用右值引用实现移动语义?

参考文献:利用移动语义优化 C++ 程序性能的实用指南_c++什么是移动语义-CSDN博客

定义

移动语义允许资源的“移动”而不是“拷贝”。在传统的 C++ 中,当一个对象被赋值或传递给函数时,通常会发生拷贝操作,这会导致性能下降,尤其是在处理大型对象时。移动语义通过引入右值引用和移动构造函数、移动赋值运算符,允许程序员将资源的所有权从一个对象转移到另一个对象,而不是进行深拷贝。

作用

旨在提高对象的移动效率和减少资源的不必要拷贝. 传统的拷贝构造函数和赋值运算符会在对象间进行深拷贝,即将原始对象的数据复制到一个新的对象中。而移动语义则允许我们将资源从一个对象转移到另一个对象,而无需进行深拷贝。

class Test{
public:
    int* m_num;
    Test():m_num(new int(100))
    {
        cout<<"构造函数"<<endl;    
    }
    Test(const Test& a):m_num(new int(*a.m_num)){
        cout<<"拷贝构造"<<endl;    
    }
    ~Test(){
        delete m_num;    
    }
};
Test getobj(){
    Test t;
    return t;
}
int main(){
    Test t=getobj();
    cout<<"*t.m_num"<<endl;
    return 0;
}

这段代码调用了两次拷贝构造,当getobj()函数里以值的形式返回时,调用一次拷贝构造,当main里将返回的临时变量赋值给对象t,调用一次拷贝构造(但是,由于编译器RVO优化,这段代码只输出一次拷贝构造)

class Test{
public:
    int* m_num;
    Test():m_num(new int(100))
    {
        cout<<"构造函数"<<endl;    
    }
    Test(const Test& a):m_num(new int(*a.m_num)){
        cout<<"拷贝构造"<<endl;    
    }
    Test(Test&& a):m_num(*a.m_num){
        a.m_num=nullptr;
        cout<<"移动构造"<<endl;    
    }
    ~Test(){
        delete m_num;    
    }
};
Test getobj(){
    Test t;
    return t;
}
int main(){
    Test t=getobj();
    cout<<"*t.m_num"<<endl;
    return 0;
}
  • 在上面的代码中添加了 移动构造函数(参数为右值引用类型),这样在进行 Test t=getObj();并没有调用构造函数进行深拷贝,而是调用的(浅拷贝)移动构造,提高了性能。
  • 本例子中,getObj()返回值是一个右值,在进行赋值操作的时候如果等号 右边是一个右值,那么移动构造函数就会被调用。

右值引用

左值是指在内存中有明确的地址,我们可以找到这块地址的数据(可取地址,有名字)

右值是只提供数据,无法找到地址(不可取地址,没有名字)

可以使用move将左值转换为右值

实现移动语义

移动构造

#include<iostream>
using namespace std;

class A {
    int* p;
public:
    A(){
        p = nullptr;
    }
    A(int* p) {
        this->p = p;
        cout << "构造函数"<<endl;
    }
    A(A&& other) {
        this->p = other.p;
        other.p = nullptr;
        cout << "移动构造" << endl;
    }
    
};
int main() {
    A a(new int(30));
    A b = move(a);


}

移动复制运算符

#include<iostream>
using namespace std;

class A {
    int* p;
public:
    A(){
        p = nullptr;
    }
    A(int* p) {
        this->p = p;
        cout << "构造函数"<<endl;
    }            this->p = other.p;
    A& operator=(A&& other) {
        if (p) p = nullptr;
        this->p = other.p;
        other.p = nullptr;
        cout << "赋值运算符" << endl;
        return *this;
    }
};
int main() {
    A a(new int(30));
    A b;
    b= move(a);

}
输出结果
//构造函数
//赋值运算符


http://www.kler.cn/a/404422.html

相关文章:

  • 2411rust,1.75.0
  • java: spire.pdf.free 9.12.3 create pdf
  • uniapp vue3小程序报错Cannot read property ‘__route__‘ of undefined
  • android 使用MediaPlayer实现音乐播放--获取音乐数据
  • 数据集-目标检测系列- 花卉 鸡蛋花 检测数据集 frangipani >> DataBall
  • 【蓝桥杯C/C++】翻转游戏:多种实现与解法解析
  • 学习threejs,导入FBX格式骨骼绑定模型
  • 萤石设备视频接入平台EasyCVR私有化视频平台视频监控系统的需求及不同场景摄像机的选择
  • 无人机无刷电机核心算法!
  • 网络安全概论
  • 【mysql】锁机制 - 3.意向锁
  • GPT-1.0、GPT-2.0、GPT-3.0参数对比
  • 本地maven添加jar包
  • 美畅物联丨智能分析,安全管控:视频汇聚平台助力智慧工地建设
  • PyTorch——从入门到精通:PyTorch基础知识(normal 函数)【PyTorch系统学习】
  • 【英特尔IA-32架构软件开发者开发手册第3卷:系统编程指南】2001年版翻译,2-30
  • CSS中calc语法不生效
  • Android 从本地选择视频,用APP播放或进行其他处理
  • 缓冲区的奥秘:解析数据交错的魔法
  • C#(12) 内部类和分部类
  • 弹幕发送功能‘简单’实现
  • 数据集论文:面向深度学习的土地利用场景分类与变化检测
  • 设计模式-Adapter(适配器模式)GO语言版本
  • 2024信创数据库TOP30之达梦DM8
  • php:nginx如何配置WebSocket代理?
  • 接雨水