文章目录
- 定义
- 性质
- 移动构造的定义
- 实例代码分析
- 移动构造 与 拷贝构造的比较
- 移动赋值 和 拷贝赋值
- 应用场景
定义
移动构造(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;
}
对于上述代码,当执行的是拷贝构造+拷贝赋值时:
可以看出拷贝构造时 进行了两次深拷贝
而当执行的是移动构造+移动赋值时:
此时仅有一次资源移动
应用场景
-
对于临时对象:当有一个临时对象(右值),并且希望将其资源转移给其他对象,而不进行深拷贝时,可以使用移动构造。移动构造会以低开销地将资源从临时对象转移到目标对象,避免了不必要的资源拷贝。
-
对于大型对象:如果对象比较大且复制操作开销较大,那么使用移动构造可以提高性能。通过移动构造,可以避免进行昂贵的深拷贝,而仅仅是移动指针或资源所有权,从而更高效地创建新对象。
-
对于资源管理类:当你编写需要管理底层资源(如内存、文件句柄等)的类时,移动构造可以实现资源的转移和所有权的转移。例如,当一个对象被赋值给另一个对象时,可以通过移动构造将资源从源对象转移到目标对象,同时确保源对象在析构时不会释放资源。
-
对于容器类:在使用容器类(如向量、列表等)时,如果需要在容器之间转移元素而不是进行深拷贝,可以使用移动构造。这可以减少元素的拷贝数量,并提高插入、删除等操作的性能。
即:移动构造适用于需要转移资源所有权、避免不必要的拷贝、提高性能或实现资源管理的情况下。它通常用于处理临时对象、大型对象和涉及资源管理的类和容器。