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

C++ 移动语义

移动语义

C++11中提供了一个新特性-移动语义,使用std::move实现,用法为

std::move

MyClass A;
MyClass B = std::move(A);

移动语义的意义是当一个临时变量生命周期要结束了,但是需要使用其初始化另外一个变量,例如函数的返回值(非指针),就是一个临时变量。我们知道,使用一个类去初始化另外一个类可以使用拷贝的方式,即调用类的拷贝构造函数或赋值运算符函数,为了防止类中内容出现指针悬垂情况,类的拷贝构造和赋值运算符都会写成深拷贝的模式,即需要重新申请一块内存再将数据存放进去。而移动语义则是直接占为己有,即把数据直接转移到另一个实例化的类中,避免了拷贝带来的性能花销。std::move函数的用处就是告诉编译器,这个对象已经不需要了,可以直接转给别的类使用。
下面展示一个例子:

#include <iostream>
#include <vector>

using namespace std;
class MyClass
{
public:

	MyClass(const char* _name) {
		id = 0;
		name = new char[256];
		memset(name, 0, 256);
		strcpy_s(this->name, 256, _name);
		cout << "Call Constructor, name address = " << static_cast<void*>(name) << endl;
	}

	MyClass(const MyClass& other) {
		if (this->name)
			delete this->name;
		this->name = new char[256];
		memset(this->name, 0, 256);
		strcpy_s(this->name, 256, other.name);
		this->id = other.id;
		cout << "Call Copy Constructor, name address = " << static_cast<void*>(name) << endl;
	}

	~MyClass() {
		cout << "Call Destructor, name address = " << static_cast<void*>(name) << endl;
		if (name)
			delete[] name;
	}

private:
	int id;
	char* name = nullptr;
};

MyClass func()
{
	return MyClass("aaa");
}

int main()
{
	MyClass a = move(func());
	MyClass b = func();
}

运行这段代码会发现拷贝构造函数被调用了,原因是因为类中没有定义移动构造函数,编译器只能去调用拷贝构造函数。

移动构造函数

下面就来实现移动拷贝构造函数。为了实现移动语义,C++11新增了一个新特性,叫做右值引用,使用双&定义。单一&定义的是左值引用。

int a = 0;
int& b = a;	// 左值引用
int&& c;	// 右值引用

让编译器将一个变量匹配成右值引用的情况有两个

  1. 一个在执行语句后就会被释放的临时变量
  2. 使用std::move标记的变量

将变量匹配成右值引用是实现移动语义的基础

实现移动构造函数的思路就是移动语义的含义,直接将另一个类的数据内存直接接管,同时还需要注意一个重点,就是把传入对象的数据清除。
移动构造函数的参数就是上述说的右值引用,在上述类中添加上移动构造函数:

// 实现深拷贝类
class MyClass
{
public:

	MyClass(const char* _name) {
		id = 0;
		name = new char[256];
		memset(name, 0, 256);
		strcpy_s(this->name, 256, _name);
		cout << "Call Constructor, name address = " << static_cast<void*>(name) << endl;
	}

	MyClass(const MyClass& other) {
		if (this->name)
			delete this->name;
		this->name = new char[256];
		memset(this->name, 0, 256);
		strcpy_s(this->name, 256, other.name);
		this->id = other.id;
		cout << "Call Copy Constructor, name address = " << static_cast<void*>(name) << endl;
	}

	// 移动构造函数
	MyClass(MyClass&& other) noexcept {
		this->id = move(other.id);
		// 直接移动
		this->name = other.name;
		// move对原始指针没用,直接接管即可
		other.name = nullptr;
		cout << "Call Move Constructor, name address = " << static_cast<void*>(name) << endl;
	}

	MyClass& operator=(const MyClass& other) {
		if (this != &other)
		{
			if (this->name)
				delete this	->name;
			this->name = new char[256];
			memset(this->name, 0, 256);
			strcpy_s(this->name, 256, other.name);
			this->id = other.id;
		}
		cout << "Call operator, name address = " << static_cast<void*>(name) << endl;
		return *this;
	}

	~MyClass() {
		cout << "Call Destructor, name address = " << static_cast<void*>(name) << endl;
		if (name)
			delete[] name;
	}

private:
	int id;
	char* name = nullptr;
};

总结

当出现一些只为了提供给另外一个类实例化的变量时,例如函数返回临时变量或是将一个实例化的类push_back到vector中而无其他用处,就可以使用移动语义的方式,以减少程序运行时出现的拷贝,减少性能消耗。

相关文章:

  • 电商API安全防护:JWT令牌与XSS防御实战
  • Java EE初阶-计算机导论
  • 15增减字符串匹配(贪心)思路解析+源码
  • 分布式 IO 模块:造纸设备的降本增效利器
  • 算法专题(四):前缀和
  • 累加器(Accumulators)在Spark中的应用
  • 收到线上服务器出现cpu告警一般怎么排查?
  • pytorch基础
  • 如何保证bug在改完之后不会引起新bug
  • 读书笔记-高性能mysql(理解mysql知识点)
  • 【CS285】听说过“欧氏距离”,这个“马氏距离(Mahalanobis distance)”又是什么呀?
  • Redis复制性能优化利器:深入解析replica-lazy-flush参数
  • 深入解析内存池设计:从原理到手动实现
  • 推荐几款开源免费的 .NET MAUI 组件库
  • 2025-2-21 leetcode刷题情况(二叉树的修改与构造)
  • python面试题整理
  • 基于STM32的智能电力监测与需求响应系统
  • vue3 文件类型传Form Data数据格式给后端
  • 骶骨神经
  • GB28181协议详解
  • 如果做淘宝网站/百度联盟广告点击一次收益
  • 有实力高端网站设计地址/关键字搜索软件
  • 沈阳网站建设/什么是优化
  • 太原企业网站制作/上海seo推广方法
  • 网站开发层次/谷歌关键词搜索排名
  • 阿里云做网站需要环境/持啊传媒企业推广