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

C++拷贝构造后修改新对象值导致原对象值同步改变问题

问题根源

修改v4元素时同步改动v2的核心原因是拷贝构造、拷贝赋值运算符中std::memcpy的参数完全传错,导致浅拷贝问题:

  • 你写的std::memcpy(&data, &(v.data), v.elements);中,前两个参数传的是两个对象里data指针变量自身的地址,而非指针指向的堆数组首地址:&data是当前对象中存放指针的栈内存地址,&v.data是源对象中存放指针的栈内存地址。执行这句代码时,会直接把源对象data存储的地址值拷贝覆盖当前对象的data值,相当于你刚给新对象new出来的独立内存直接泄漏,两个对象的data最终指向同一块堆内存,修改其中一个的元素自然会影响另一个。
  • 第三个参数传了元素个数v.elements,但std::memcpy要求传入待拷贝的总字节数,就算前两个地址写对,这里长度不对也无法完成正确的元素拷贝。
  • 额外的小语法问题:main函数中vec v4 = v2末尾缺少分号,无法正常编译。
  • 额外的内存泄漏隐患:类没有定义析构函数释放动态申请的数组内存,程序运行会产生内存泄漏。
修正方案
  1. 修正std::memcpy的三个参数:
    • 目标地址直接传data(新对象new出来的数组首地址)
    • 源地址直接传v.data(源对象存储元素的数组首地址)
    • 拷贝长度传v.elements * sizeof(double)(所有元素占的总字节数)
  2. 补全析构函数,补上main函数里缺失的分号。

修正后的核心代码如下:

class vec {
private:
    size_t elements;
    double* data;

public:
    vec(size_t size) : elements{ size }, data{ new double[size] } {
        std::cout << "First constructor" << "\n"; 
    };
    
    vec(size_t size, double ival) : elements{ size }, data{ new double[size] } {
        std::cout << "Second constructor" << std::endl;
        for (size_t i = 0; i < elements; i++) {
            data[i] = ival;
        }
    }
    
    vec(std::initializer_list<double> iList): vec(static_cast<size_t>(iList.size())) {
        std::cout << "Third constructor" << std::endl;
        size_t count{ 0 };
        for (auto element: iList) {
            data[count] = element;
            count++;
        }
    }
    
    // 修正拷贝构造
    vec(const vec& v) : elements{ v.elements }, data{ new double[v.elements] }{
        std::cout << "Copy constructor " << "\n";
        std::memcpy(data, v.data, v.elements * sizeof(double));
    }
    
    // 补全析构函数
    ~vec() {
        delete[] data;
    }
    
    // 修正拷贝赋值,同时优化为异常安全的写法:先拷贝新数据再释放旧内存
    vec& operator=(const vec& v) {
        std::cout << "Copy assignment " << "\n";
        if (this != &v) {
            const auto new_data{ new double[v.elements] };
            std::memcpy(new_data, v.data, v.elements * sizeof(double));
            delete[] data;
            data = new_data;
            elements = v.elements;
        }
        return *this;
    }
    
    double& operator[](size_t idx){
        return this->data[idx];
    }
    
    friend std::ostream& operator<<(std::ostream& os, const vec& v) {
        for (size_t i = 0; i < v.elements; i++) {
            os << v.data[i] << "\n";
        }
        return os;
    }
};

int main(void) {
    vec v2 = {4, 5, 6};
    vec v4 = v2; // 补全缺失的分号

    v4[0] = 11;
    v4[1] = 12;

    return 0;
}

修正后v2和v4持有独立的堆内存,修改v4的元素不会对v2产生任何影响。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.02 03:12:33