MST

星途 面试题库

面试题:C++ 拷贝构造函数性能优化之移动语义

简述 C++ 中移动语义是如何优化拷贝构造函数性能的。请实现一个包含动态内存分配的类,同时提供拷贝构造函数和移动构造函数,并说明移动构造函数是怎样避免不必要的内存复制从而提升性能的。
43.1万 热度难度
编程语言C++

知识考点

AI 面试

面试题答案

一键面试

移动语义优化拷贝构造函数性能简述

在 C++ 中,拷贝构造函数会完整地复制对象的内容,这对于包含动态分配内存的对象来说,开销较大。移动语义允许将资源(如动态分配的内存)从一个对象转移到另一个对象,而不是进行深度复制。这样可以避免不必要的内存分配和释放操作,从而提升性能。具体来说,移动构造函数通过 “窃取” 源对象的资源,而不是复制资源,来创建新对象,使得源对象处于可析构的状态(通常是将源对象的指针置为 nullptr 等操作)。

包含动态内存分配的类及相关构造函数实现

#include <iostream>
#include <cstring>

class MyString {
private:
    char* data;
    size_t length;

public:
    // 构造函数
    MyString(const char* str = nullptr) {
        if (str == nullptr) {
            length = 0;
            data = new char[1];
            data[0] = '\0';
        } else {
            length = std::strlen(str);
            data = new char[length + 1];
            std::strcpy(data, str);
        }
    }

    // 拷贝构造函数
    MyString(const MyString& other) {
        length = other.length;
        data = new char[length + 1];
        std::strcpy(data, other.data);
    }

    // 移动构造函数
    MyString(MyString&& other) noexcept {
        data = other.data;
        length = other.length;
        other.data = nullptr;
        other.length = 0;
    }

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

    // 重载赋值运算符
    MyString& operator=(const MyString& other) {
        if (this == &other) {
            return *this;
        }
        delete[] data;
        length = other.length;
        data = new char[length + 1];
        std::strcpy(data, other.data);
        return *this;
    }

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

    void print() const {
        std::cout << data << std::endl;
    }
};

移动构造函数避免不必要内存复制的说明

在上述 MyString 类的移动构造函数中,并没有像拷贝构造函数那样重新分配内存并复制数据。而是直接将源对象 otherdata 指针和 length 成员变量接管过来,然后将 otherdata 指针置为 nullptrlength 设为 0。这样,新对象就拥有了源对象的资源,而源对象处于一个可析构的状态(释放 nullptr 不会有问题)。避免了重新分配内存和复制数据的操作,从而提升了性能。例如,当使用移动构造函数从一个临时对象创建新对象时,无需进行深度复制,大大提高了效率。