c++ 移动语义 完美转发

本文详细介绍了C++中的移动语义及其应用场景,旨在减少对象拷贝提高效率。移动构造函数和移动赋值操作符通过右值引用实现资源的转移而非复制。同时,文章还探讨了完美转发的概念,用于在函数参数传递中保持原始参数类型不变,确保高效地调用构造函数或成员函数。完美转发的关键在于使用万能引用和std::forward。
摘要由CSDN通过智能技术生成

移动语义

移动语义的使用场景

在写代码的时候会出现低效拷贝。如在string s1 = get_str();中先构造了一个临时对象,然后将这个临时对象拷贝赋值给了s1。
最高效的操作应该是s1直接表示get_str中构造的s内存。
移动语义的实现就是为了减少拷贝。

string get_str(){
    string s;
    ...
    return s;
}
int main(){
    string s1 = get_str();
}

移动语义的使用

实现移动语义,就是实现类的移动赋值函数移动拷贝函数

class Array {
	Array(int sz);

	Array(const Array& other);//拷贝构造函数
	Array& operator = (const Array & other); //拷贝赋值函数
	
	Array(const Array&& other);//移动构造函数
	Array& operator = (const Array && other);//移动赋值函数

	~Array(); //析构函数
private:
	size_t sz; //记录资源个数
	int* m_data; //指向资源的指针
};

在语法上,拷贝函数参数是左值引用,移动函数参数是右值引用
在实现上,拷贝函数被拷贝的原对象不会有改变,自身的值变为拷贝对象的值;移动函数不保证原对象的值会变成什么样,只保证原对象的状态是安全的,可析构的,原对象的值“移动”给自身用。

class Array {
	...
	//拷贝构造函数
	Array(const Array& other) {
		sz = other.sz;

		m_data = new int[sz];
		for (size_t i = 0; i < sz; i++)
			...//拷贝数据
	
	}
	//拷贝赋值函数	
	Array& operator = (const Array& other){
		sz = other.sz;

		delete[] m_data;
		m_data = new int[sz];
		for (size_t i = 0; i < sz; i++)
			...//拷贝数据
	}
	
	//移动构造函数
	Array(const Array&& other) {
		sz = other.sz;

		m_data = other.m_data;
		other.m_data = nullptr;
		other.sz = 0;
	}
	//移动赋值函数
	Array& operator = (const Array&& other) {
		sz = other.sz;

		m_data = other.m_data;
		other.m_data = nullptr;
		other.sz = 0;
	}
	...
};

在使用上,左值引用只能绑定左值,右值引用只能绑定右值。(const左值引用特殊,可以绑定右值)。
因此要声明一个右值引用应该使用move。
move底层实现是使用static_cast完成了一个类型转换,并没有实际的移动的操作。

int main() {
	Array a1(10);
	Array& lref = a1;
	Array a3(a1); //拷贝初始化
	Array a4(lref);//拷贝初始化

	Array&& a4 = a1;//错误,右值引用不能绑定左值
	Array&& a5 = move(a1);
	Array a4(a5);//移动初始化

PS:右值和左值的区别
左值:有一定的生命周期
右值:生命期一般不超过一句话,辅助表达式的执行(如临时对象)
所以右值引用是左值。

完美转发

完美转发的使用场景

在一些函数中,一些参数是需要转发给另外的函数的
比如标准库revoke(f,args...)执行f(args...)
比如vector的emplace_back(args...) ,会在vector的尾部利用args来构造一个类,需要调用构造函数。
完美转发就是希望在传参时,传入的类型不变。如果args是左值引用的,那么传给构造函数的也应该是左值引用;如果args是右值引用的,那么传给构造函数的也应该是右值引用。

完美转发的使用

参数传入要写成万能引用,转发时调用forward

template<typename Func,typename T>
auto myInvoke(Func f,T&& arg){
	return f(std::forward<T>(arg));
}

T&& arg是万能引用的写法,详见这个博客

必看:
大佬视频,深入又清晰

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值