使用一个简单的动态数组类来演示如何利用右值引用实现移动构造和移动赋值。
示例代码:动态数组类
#include <iostream>
#include <utility> // for std::move
class DynamicArray {
public:
DynamicArray(size_t size) : size(size), data(new int[size]) {
std::cout << "Constructing array of size: " << size << std::endl;
}
// 移动构造函数
DynamicArray(DynamicArray&& other) noexcept : size(other.size), data(other.data) {
other.size = 0; // 清空原对象的大小
other.data = nullptr; // 清空原对象的数据指针
std::cout << "Moving array." << std::endl;
}
// 析构函数
~DynamicArray() {
delete[] data; // 释放内存
std::cout << "Destructing array." << std::endl;
}
void set(size_t index, int value) {
if (index < size) {
data[index] = value;
}
}
void print() const {
for (size_t i = 0; i < size; ++i) {
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
private:
size_t size; // 数组大小
int* data; // 动态分配的数组
};
DynamicArray createArray() {
DynamicArray arr(5); // 创建一个大小为5的数组
for (size_t i = 0; i < 5; ++i) {
arr.set(i, i * 10); // 设置数组元素
}
return arr; // 返回临时对象
}
int main() {
DynamicArray myArray = createArray(); // 调用移动构造函数
myArray.print(); // 打印数组内容
return 0; // 离开作用域时,myArray 被销毁
}
代码解释
-
类
DynamicArray
:- 有一个构造函数,接受数组大小并动态分配内存。
- 移动构造函数
DynamicArray(DynamicArray&& other)
,将原对象的资源转移到新对象。这里会转移数组的大小和数据指针,同时将原对象的状态重置为不再指向有效的内存,避免析构时重复释放。 - 析构函数释放动态分配的内存。
-
返回临时对象:
- 函数
createArray()
创建一个DynamicArray
对象,并返回。当该对象超出作用域时,调用移动构造函数将其资源转移到调用者。
- 函数
-
主函数
main
:- 调用
createArray()
,并将返回的临时对象赋值给myArray
。这会触发移动构造。 - 最后,当
main
函数结束时,myArray
被销毁,执行其析构函数。
- 调用
在这个示例中:
- 首先构造了动态数组。
- 然后通过移动构造将资源转移给
myArray
。 - 最后,程序结束时,
myArray
被销毁,调用析构函数释放内存。
关于对象
-
对象的创建和移动:
- 在
main
函数中,createArray()
被调用,创建了一个DynamicArray
对象。这时会调用构造函数,输出 "Constructing array of size: 5"。 - 当
createArray()
返回时,返回的是一个右值(一个临时对象),所以会调用移动构造函数,将这个临时对象的资源转移到myArray
中。这时候输出 "Moving array."。
- 在
-
对象的销毁:
- 当
createArray()
返回时,临时对象将被销毁,因为临时对象的生命周期只持续到表达式结束。这将触发该临时对象的析构函数,输出 "Destructing array."。 - 接下来,
myArray
在main
函数结束后也会被销毁,这时候会再次调用myArray
的析构函数,同样输出 "Destructing array."。
- 当
代码逻辑顺序
1. 对象的构造
当 createArray()
被调用时,创建了一个动态数组:
DynamicArray arr(5); // 这里构造了动态数组
输出:
Constructing array of size: 5
2. 设置数组元素
随后的循环会为每个元素设置值(0, 10, 20, 30, 40),但这个过程没有直接的输出,只是将这些值储存在数组中。
3. 返回临时对象
返回临时对象时,调用了移动构造函数:
return arr; // 返回临时对象
此时输出:
Moving array.
4. 主函数接收对象
在 main
函数中:
DynamicArray myArray = createArray(); // 使用移动构造,将临时对象的资源转移到 myArray
此时,原来的临时对象 arr
的资源已被转移到 myArray
,临时对象的生命周期结束,调用了临时对象的析构函数:
Destructing array.
5. 打印数组内容
接下来,会调用 myArray
的 print()
方法:
myArray.print(); // 打印数组内容
此时会输出:
0 10 20 30 40
注意:myArray
现在持有从临时对象转移过来的数据,因此可以输出其内容。
6. 主函数结束时的析构
最后,myArray
在 main
结束后被销毁,调用其析构函数,输出:
Destructing array.
输出顺序总结
因此,整个输出的顺序是:
Constructing array of size: 5
Moving array.
Destructing array. // 临时对象 arr 被销毁
0 10 20 30 40 // 输出 myArray 的内容
Destructing array. // myArray 被销毁