MST

星途 面试题库

面试题:C++ 移动语义在自定义容器中的实现

假设你要设计一个自定义的容器类MyContainer,需要在其中支持移动语义。请描述你会如何实现移动构造函数和移动赋值运算符,以确保在向MyContainer中添加元素或对其进行赋值操作时,能高效利用移动语义。同时,阐述如何处理资源所有权的转移。
32.1万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试
  1. 移动构造函数

    • 移动构造函数的目的是从另一个对象“窃取”资源,而不是复制它们。
    • 对于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指针设为nullptrsize设为0,以确保other对象处于一个有效但“空”的状态,这样在other对象析构时不会错误地释放已经被转移走的资源。
  2. 移动赋值运算符

    • 移动赋值运算符的作用是将一个对象的资源移动到另一个对象中,并处理目标对象原来可能持有的资源。
    • 实现如下:
    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,以支持链式赋值。
  3. 处理资源所有权的转移

    • 在移动构造函数和移动赋值运算符中,资源所有权的转移通过直接接管源对象的资源指针,并将源对象的资源指针设为nullptr来实现。
    • 这样,源对象不再拥有资源,新对象成为资源的所有者。在析构函数中,只需释放自己持有的资源(如果资源指针不为nullptr),从而避免了资源的重复释放和内存泄漏。例如,MyContainer的析构函数可以这样写:
    class MyContainer {
    private:
        int* data;
        size_t size;
    public:
        ~MyContainer() {
            delete[] data;
        }
    };
    
    • 当对象被销毁时,析构函数会检查data指针,如果它不为nullptr,就释放相关资源,由于移动操作已经将资源从源对象转移走并将源对象的指针设为nullptr,所以不会出现重复释放的问题。