MST

星途 面试题库

面试题:C++ 移动构造函数性能优化中的资源管理

假设有一个包含动态分配数组的 C++ 类,在实现移动构造函数时,如何确保资源的正确转移并且提升性能,同时避免内存泄漏和悬空指针问题?请给出具体的代码实现,并说明关键步骤和原理。
17.2万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

代码实现

#include <iostream>
#include <cstring>

class DynamicArray {
private:
    int* data;
    size_t size;

public:
    // 构造函数
    DynamicArray(size_t s) : size(s) {
        data = new int[size];
        std::memset(data, 0, size * sizeof(int));
    }

    // 析构函数
    ~DynamicArray() {
        delete[] data;
    }

    // 拷贝构造函数
    DynamicArray(const DynamicArray& other) : size(other.size) {
        data = new int[size];
        std::memcpy(data, other.data, size * sizeof(int));
    }

    // 移动构造函数
    DynamicArray(DynamicArray&& other) noexcept : size(other.size), data(other.data) {
        other.data = nullptr;
        other.size = 0;
    }

    // 拷贝赋值运算符
    DynamicArray& operator=(const DynamicArray& other) {
        if (this != &other) {
            delete[] data;
            size = other.size;
            data = new int[size];
            std::memcpy(data, other.data, size * sizeof(int));
        }
        return *this;
    }

    // 移动赋值运算符
    DynamicArray& operator=(DynamicArray&& other) noexcept {
        if (this != &other) {
            delete[] data;
            size = other.size;
            data = other.data;
            other.data = nullptr;
            other.size = 0;
        }
        return *this;
    }
};

关键步骤和原理

  1. 参数声明:移动构造函数的参数是一个右值引用 DynamicArray&& other,表明这个构造函数处理的是一个即将被销毁的对象。noexcept 关键字表明该函数不会抛出异常,有助于编译器进行优化。
  2. 资源转移:在移动构造函数中,直接将源对象 other 的资源(data 指针和 size)转移到新对象。这是通过将 other.data 赋值给新对象的 data,以及将 other.size 赋值给新对象的 size 来实现的。
  3. 源对象重置:为了避免源对象在析构时释放已转移的资源(从而导致悬空指针问题),需要将源对象的 data 指针设为 nullptr,并将 size 设为 0。这样,当源对象析构时,它不会尝试释放已经不属于它的内存。
  4. 性能提升:与拷贝构造函数不同,移动构造函数不需要分配新的内存并逐个复制元素,因此在性能上有显著提升,尤其是对于大型数组。它只是简单地转移资源的所有权,这是一种非常高效的操作。