面试题答案
一键面试右值引用实现移动语义原理
在C++中,右值引用(&&
)用于标识临时对象或即将销毁的对象。移动语义利用右值引用,允许我们将资源(如动态分配的内存)从一个对象高效地转移到另一个对象,而不是进行深拷贝。这样可以避免不必要的内存分配和释放操作,提高程序性能。
当一个对象作为右值传递给函数或构造函数时,我们可以通过右值引用参数来接收它,并在内部将其资源“移动”到新对象,同时将原对象置为一个可析构的状态(通常是将其内部指针设为 nullptr
等)。
示例代码
#include <iostream>
#include <memory>
class MyClass {
private:
std::unique_ptr<int[]> data;
size_t size;
public:
// 构造函数
MyClass(size_t s) : size(s), data(std::make_unique<int[]>(s)) {
std::cout << "Constructor: Allocating memory for " << size << " elements." << std::endl;
}
// 析构函数
~MyClass() {
std::cout << "Destructor: Deallocating memory." << std::endl;
}
// 拷贝构造函数
MyClass(const MyClass& other) : size(other.size), data(std::make_unique<int[]>(other.size)) {
std::cout << "Copy Constructor: Copying data." << std::endl;
for (size_t i = 0; i < size; ++i) {
data[i] = other.data[i];
}
}
// 拷贝赋值运算符重载
MyClass& operator=(const MyClass& other) {
if (this != &other) {
size = other.size;
data = std::make_unique<int[]>(size);
std::cout << "Copy Assignment: Copying data." << std::endl;
for (size_t i = 0; i < size; ++i) {
data[i] = other.data[i];
}
}
return *this;
}
// 移动构造函数
MyClass(MyClass&& other) noexcept : size(other.size), data(std::move(other.data)) {
other.size = 0;
other.data = nullptr;
std::cout << "Move Constructor: Moving data." << std::endl;
}
// 移动赋值运算符重载
MyClass& operator=(MyClass&& other) noexcept {
if (this != &other) {
size = other.size;
data = std::move(other.data);
other.size = 0;
other.data = nullptr;
std::cout << "Move Assignment: Moving data." << std::endl;
}
return *this;
}
};
int main() {
MyClass a(5);
MyClass b = std::move(a); // 调用移动构造函数
MyClass c(10);
c = std::move(b); // 调用移动赋值运算符重载
return 0;
}
在上述代码中:
- 移动构造函数:
MyClass(MyClass&& other) noexcept
接收一个右值引用参数other
,将other
的资源(data
和size
)移动到当前对象,同时将other
置为可析构的状态。 - 移动赋值运算符重载:
MyClass& operator=(MyClass&& other) noexcept
同样接收一个右值引用参数other
,先检查是否为自赋值,然后将other
的资源移动到当前对象,并将other
置为可析构的状态。
通过 std::move
函数可以将左值转换为右值,从而触发移动语义。在 main
函数中,通过 std::move
调用了移动构造函数和移动赋值运算符重载。