面试题答案
一键面试-
移动构造函数
- 移动构造函数的目的是从另一个对象“窃取”资源,而不是复制它们。
- 对于
MyContainer
类,假设它包含一些动态分配的资源(例如一个动态数组),移动构造函数的实现如下:
class MyContainer { private: int* data; size_t size; public: // 移动构造函数 MyContainer(MyContainer&& other) noexcept { data = other.data; size = other.size; other.data = nullptr; other.size = 0; } };
- 在上述代码中:
- 我们将
other
对象的data
指针和size
成员直接拿过来,这是资源所有权的转移。 - 然后将
other
对象的data
指针设为nullptr
,size
设为0,以确保other
对象处于一个有效但“空”的状态,这样在other
对象析构时不会错误地释放已经被转移走的资源。
- 我们将
-
移动赋值运算符
- 移动赋值运算符的作用是将一个对象的资源移动到另一个对象中,并处理目标对象原来可能持有的资源。
- 实现如下:
class MyContainer { private: int* data; size_t size; public: // 移动赋值运算符 MyContainer& operator=(MyContainer&& other) noexcept { if (this != &other) { delete[] data; data = other.data; size = other.size; other.data = nullptr; other.size = 0; } return *this; } };
- 在上述代码中:
- 首先检查是否是自赋值(
this != &other
),如果是自赋值则直接返回自身。 - 然后释放目标对象(
this
所指对象)原来持有的资源(delete[] data
)。 - 接着像移动构造函数一样,从
other
对象转移资源,将other
对象置为有效但“空”的状态。 - 最后返回
*this
,以支持链式赋值。
- 首先检查是否是自赋值(
-
处理资源所有权的转移
- 在移动构造函数和移动赋值运算符中,资源所有权的转移通过直接接管源对象的资源指针,并将源对象的资源指针设为
nullptr
来实现。 - 这样,源对象不再拥有资源,新对象成为资源的所有者。在析构函数中,只需释放自己持有的资源(如果资源指针不为
nullptr
),从而避免了资源的重复释放和内存泄漏。例如,MyContainer
的析构函数可以这样写:
class MyContainer { private: int* data; size_t size; public: ~MyContainer() { delete[] data; } };
- 当对象被销毁时,析构函数会检查
data
指针,如果它不为nullptr
,就释放相关资源,由于移动操作已经将资源从源对象转移走并将源对象的指针设为nullptr
,所以不会出现重复释放的问题。
- 在移动构造函数和移动赋值运算符中,资源所有权的转移通过直接接管源对象的资源指针,并将源对象的资源指针设为