【c++11】移动构造的性质 和 与拷贝构造的比较(详解)

定义

移动构造(Move Constructor)是一种特殊的构造函数,它通过接收一个右值引用参数来创建新对象,并从传入的对象中“移动”资源而不是执行深拷贝。

移动构造的使用场景:

  • 在函数中返回临时对象时,可以通过移动构造函数避免不必要的拷贝操作。

  • 在容器中插入临时对象时,可以通过移动构造函数实现高效插入和删除操作。

  • 在进行资源管理时,通过移动构造函数可以从一个对象转移资源所有权,提高性能。


性质

移动构造本质是将参数右值的资源窃取过来,占位已有,那么就不 用做深拷贝了,所以它叫做移动构造,就是窃取别人的资源来构造自己。

移动构造的定义

由于移动构造函数的参数为右值引用参数,所以遵循下面的写法:

class MyClass {
public:
    // 移动构造函数
    MyClass(MyClass&& other) {
        // 资源的转移或交换操作
        // ...
    }
};

实例代码分析

下面的代码 是自定义的string 类,省略了部分功能/代码,用来作分析:

namespace aiyimu
{
	class string
	{
	public:
		// 构造函数
		string(const char* str = "")
			:_size(strlen(str))
			, _capacity(_size)
		{
			_str = new char[_capacity + 1];
			strcpy(_str, str);
		}

		void swap(string& s)
		{
			::swap(_str, s._str); //std::swap -> ::swap
			::swap(_size, s._size);
			::swap(_capacity, s._capacity);
		}

		// 拷贝构造
		string(const string& s)
			:_str(nullptr)
		{
			cout << "string(const string& s) <---> 拷贝构造(深拷贝)" << endl;
			// 拷贝操作
			_str = new char[s._capacity + 1];
			strcpy(_str, s._str);
			_size = s._size;
			_capacity = s._capacity;
		}

		// 移动构造
		// 以右值引用作参数
		string(string&& s)
			:_str(nullptr)
			, _size(0)
			, _capacity(0)
		{
			cout << "string(string&& s) <---> 资源转移" << endl;
			swap(s);
		}
		
		// 拷贝赋值运算符
		string& operator=(const string& s)
		{
			cout << "string& operator=(string s) <---> 拷贝赋值(深拷贝)" << endl;
			string tmp(s);
			swap(tmp);

			return *this;
		}

		// 移动赋值运算符
		string& operator=(string&& s)
		{
			cout << "string& operator=(string&& s) <---> 移动赋值(资源移动)" << endl;
			swap(s);

			return *this;
		}		

		// 析构
		~string()
		{
			delete[] _str;
			_str = nullptr;
		}

	private:
		char* _str;
		size_t _size;
		size_t _capacity;
	};
}

这里分别实现了 拷贝构造 string(const string& s) 和 移动构造 string(string&& s),下面将举例一些 适用移动构造 的情况。


移动构造 与 拷贝构造的比较

对上面定义的string类,用下面的代码进行比较:

  • 由于我们实现的 拷贝构造 的参数是const 类型,所以既可以进行左值引用也可以进行右值引用
  • 当存在移动构造时,传入右值优先调用移动构造,否则构造此时的拷贝构造。
  • 对下面的代码,to_string 的 参数是10(右值),调用移动构造,但我们讲两种构造都作讨论。
    在这里插入图片描述

在这里插入图片描述


移动赋值 和 拷贝赋值

移动赋值(Move Assignment)是一种在编程语言中用于将一个对象的资源(如内存空间)转移到另一个对象的操作。

// 移动赋值
string& operator=(string&& s)
{
	cout << "string& operator=(string&& s) <---> 移动赋值(资源移动)" << endl;
	swap(s);

	return *this;
}

通常情况下,对象的赋值操作会将源对象的值复制到目标对象中,但是在某些情况下,复制操作可能是低效或不可行的,或者我们希望避免不必要的资源拷贝。这时,移动赋值就可以派上用场。

int main()
{
	aiyimu::string ret("114");
	ret = to_string(514);
	return 0;
}

对于上述代码,当执行的是拷贝构造+拷贝赋值时:

在这里插入图片描述

可以看出拷贝构造时 进行了两次深拷贝

而当执行的是移动构造+移动赋值时:

在这里插入图片描述

此时仅有一次资源移动

应用场景

  1. 对于临时对象:当有一个临时对象(右值),并且希望将其资源转移给其他对象,而不进行深拷贝时,可以使用移动构造。移动构造会以低开销地将资源从临时对象转移到目标对象,避免了不必要的资源拷贝

  2. 对于大型对象:如果对象比较大且复制操作开销较大,那么使用移动构造可以提高性能。通过移动构造,可以避免进行昂贵的深拷贝,而仅仅是移动指针或资源所有权,从而更高效地创建新对象

  3. 对于资源管理类:当你编写需要管理底层资源(如内存、文件句柄等)的类时,移动构造可以实现资源的转移和所有权的转移。例如,当一个对象被赋值给另一个对象时,可以通过移动构造将资源从源对象转移到目标对象,同时确保源对象在析构时不会释放资源。

  4. 对于容器类:在使用容器类(如向量、列表等)时,如果需要在容器之间转移元素而不是进行深拷贝,可以使用移动构造。这可以减少元素的拷贝数量,并提高插入、删除等操作的性能。

即:移动构造适用于需要转移资源所有权、避免不必要的拷贝、提高性能或实现资源管理的情况下。它通常用于处理临时对象、大型对象和涉及资源管理的类和容器。

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值