You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++按值传递引发的对象损坏问题:请求复现示例

复现按值传递对象时因析构副作用破坏原对象的示例

Herbert Schildt提到的这种情况,核心原因是默认拷贝构造函数的浅拷贝行为。当类包含动态分配的资源(比如堆内存)时,默认拷贝只会复制指针本身,导致原对象和函数内的副本共享同一块内存。当函数执行完毕,副本的析构函数会释放这块共享内存,原对象的指针就会变成野指针,进而导致原对象被破坏,访问时触发未定义行为。

未定义拷贝构造函数的问题示例

#include <iostream>
#include <cstring>

class MyString {
private:
    char* data;
public:
    // 构造函数:动态分配内存存储字符串
    MyString(const char* str) {
        data = new char[strlen(str) + 1];
        std::cout << "[构造] 分配内存地址: " << static_cast<void*>(data) << "\n";
        strcpy(data, str);
    }

    // 析构函数:释放动态分配的内存
    ~MyString() {
        std::cout << "[析构] 释放内存地址: " << static_cast<void*>(data) << "\n";
        delete[] data;
        data = nullptr;
    }

    // 打印当前对象的字符串内容和内存地址
    void show() const {
        std::cout << "内容: " << (data ? data : "野指针(内存已释放)") 
                  << " | 内存地址: " << static_cast<void*>(data) << "\n";
    }
};

// 按值传递对象的函数
void process_string(MyString obj) {
    std::cout << "\n函数内的副本对象:\n";
    obj.show();
} // 此处调用副本的析构函数,释放共享内存

int main() {
    MyString original("Hello C++");
    std::cout << "\n调用函数前的原对象:\n";
    original.show();

    process_string(original); // 按值传递,触发默认拷贝构造

    std::cout << "\n调用函数后的原对象:\n";
    original.show(); // 原对象的内存已被副本析构释放,访问属于未定义行为

    return 0;
}

运行结果说明

  1. 程序启动后,原对象original构造,分配一块内存存储字符串,打印内容和地址。
  2. 调用process_string时,默认拷贝构造函数创建副本obj,obj的data指针和original指向同一块内存。
  3. 函数执行完毕,副本obj析构,释放共享内存。
  4. 返回main后,原对象original的data已经是野指针,此时访问它会输出乱码、“野指针”提示,甚至直接崩溃——这就是书中所说的原对象被修改/破坏的副作用。

解决方法:自定义拷贝构造函数(深拷贝)

为类添加自定义拷贝构造函数,实现深拷贝,让副本拥有独立的内存空间,这样副本析构时不会影响原对象:

// 在MyString类中添加拷贝构造函数
MyString(const MyString& other) {
    std::cout << "[拷贝构造] 为副本分配新内存\n";
    data = new char[strlen(other.data) + 1];
    strcpy(data, other.data);
}

添加后,副本和原对象的data指向不同内存,析构副本只会释放自己的内存,原对象不受影响。

内容的提问来源于stack exchange,提问作者YoussefMabrouk

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.04 15:25:16