移动构造函数与移动赋值函数
前言
拷贝构造函数创建了源对象的副本,但有些时候我们并不需要进行拷贝,而只需将源对象的资源移动到目标对象,因此C++11提供了一种新的构造方法——移动构造函数。其可以减少不必要的复制,带来性能上的提升。移动赋值函数则与移动构造函数类似,其允许将源对象的资源转移到目标对象中,并更新目标对象的状态。
移动构造函数
定义
移动的含义为:将源对象资源的控制权全部交给目标对象。
移动构造函数定义形式:
1 | |
&&符号表示右值引用,下面介绍左值引用和右值引用的相关概念。
左值引用和右值引用
左值和右值
首先介绍左值和右值的概念。左值可以取地址,位于等号左边;而右值无法取地址,位于等号右边。可以通过如下两个示例理解:
1 | |
- a可以通过&取地址,所以a是左值
- 5无法通过&取地址,所以5是右值
1 | |
- a可以通过&取地址,所以a是左值
- A()是个临时值,无法通过&取地址,所以A()是个右值。
引用
引用的本质是别名,可以通过引用修改变量的值,在传参时避免拷贝。
左值引用指的是能指向左值,不能指向右值的引用。
1 | |
左值引用是变量的别名,而右值没有地址,无法被修改,所以左值引用无法指向右值。但const左值引用可以指向右值:
1 | |
const左值引用不会修改指向值,因此可以指向右值,这也是为什么要使用const type_name &作为函数参数的原因之一。
右值引用的标志是&&,可以指向右值,不能指向左值。
1 | |
右值引用有办法指向左值吗?
可以通过std::move实现右值引用指向左值:
1 | |
std::move并不会移动什么,只是将左值强制转化为右值,让右值引用可以指向左值。而变量a依然存在,因此并不会有性能提升。
移动构造函数详解
下面我们用一个示例来详细解释移动构造函数做了什么:
1 | |
other是一个右值引用对象data = other.data让目标对象获取other的资源,不需要new新内存other.data = nullptr,将源对象指向资源的指针置空,防止原对象other销毁时释放资源
从上述示例中,我们可以得出移动构造函数可以实现不用复制资源,直接转移资源的所有权。这样一来避免了高代价的深拷贝,二来做到了零开销的资源转移。
为什么不用普通的引用而是使用右值引用?
如果使用普通引用&,程序无法区分传进来的对象是否还要继续使用。而右值引用是专门绑定右值对象的,可以放心的进行转移资源。
移动赋值函数
还是用一个例子来理解:
1 | |
首先,观察移动赋值函数做了什么:
- 判断当前对象和传入的右值对象是否是同一个,如果不是同一个:
- 将当前对象的资源指针指向传入对象的资源,并将传入对象的资源指针置空
- 返回当前对象
可以看出移动赋值函数和移动构造函数的目的一致,都是将传入对象的资源转移到目标对象。但移动赋值函数会多做一步判断,如果传入对象不是当前对象才进行移动。
参考
移动构造函数与移动赋值函数
https://delta0406.github.io/2025/05/28/技术/语言/CPP/移动构造函数与移动赋值函数/