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

如何使用std::shared_ptr重写自定义动态数组TVector的拷贝构造函数

使用std::shared_ptr重写TVector拷贝构造函数的正确方式

问题回顾

我实现了一个名为TVector的自定义动态数组类,原本的拷贝构造函数用malloc分配内存,但现在想改用std::shared_ptr来管理数组内存。尝试了下面的写法后发现不仅参数类型不对,还搞不清怎么用std::shared_ptr访问数组元素,没法完成拷贝:

原来的拷贝构造函数:

TVector::TVector(TVector &other) { 
    _size = other.length(); 
    _array = (Square*) malloc(sizeof other); 
    for(int i = 0; i < other.length(); ++i){ 
        _array[i] = other[i]; 
    } 
}

我尝试的错误代码:

TVector::TVector(std::shared_ptr<TVector> other) { 
    _size = other->length(); 
    std::shared_ptr<Square[]> _array(nullptr); 
    for(int i = 0; i < other->length(); ++i){ 
        _array[i] = other[i]; 
    } 
}

TVector类定义:

class TVector { 
public: 
    TVector(); 
    TVector(TVector& other); 
    virtual ~TVector(); 
    void Print(); 
    void push_back(const Square& value); 
    void pop_back(); 
    void clear(); 
    int length(); 
    Square& Last(); 
    Square& operator[](int idx); 
    bool empty(); 
    void resize(int count); 
    void erase(size_t pos); 
    friend std::ostream& operator<<(std::ostream& os, TVector& s); 
    friend std::istream& operator>>(std::istream& is, TVector& p); 
    int _size; 
private: 
    Square *_array; 
};

关键问题分析

你的尝试里有三个核心问题:

  1. 拷贝构造函数参数类型错误:拷贝构造的作用是从已存在的TVector对象创建新对象,参数应该是const TVector&(或非const引用),而非std::shared_ptr<TVector>——后者是用来管理TVector对象本身的智能指针,完全偏离了拷贝构造的语义。
  2. 数组版std::shared_ptr使用不当:你需要先把类内的_array从Square*改为std::shared_ptr<Square[]>(数组特化版智能指针),C++17及以后这个版本支持直接用下标运算符[],旧标准可以通过get()获取原始指针再访问元素。
  3. 原代码隐藏bug:malloc(sizeof other)是严重错误的——它分配的是TVector对象的大小,而非Square数组所需的内存,会导致内存不足、越界访问,用智能指针时必须分配对应元素数量的数组内存。

正确实现步骤

第一步:修改类成员变量

先把TVector的私有成员_array替换为数组版智能指针:

class TVector { 
    // ... 其他成员保持不变 ...
private: 
    std::shared_ptr<Square[]> _array;  // 替换原有的Square* _array;
};

第二步:重写拷贝构造函数

遵循标准拷贝构造的签名,结合std::shared_ptr<Square[]>的用法实现:

// 参数改为const TVector&,符合"拷贝不修改源对象"的语义
TVector::TVector(const TVector& other) 
    : _size(other._size) {  // 用初始化列表初始化_size,更高效
    // 方式1:直接new数组,交给shared_ptr管理
    _array = std::shared_ptr<Square[]>(new Square[_size]);
    
    // 方式2:C++20及以后推荐用make_shared(更安全,避免潜在内存泄漏)
    // _array = std::make_shared<Square[]>(_size);

    // 逐个拷贝源对象的元素
    for(int i = 0; i < _size; ++i){
        // C++17+支持直接用shared_ptr<Square[]>的[]运算符
        _array[i] = other._array[i];
        
        // 若使用C++17之前的版本,用get()获取原始指针访问
        // _array.get()[i] = other._array.get()[i];
    }
}

第三步:调整其他成员函数(必要补充)

由于_array改为智能指针,原有依赖原始指针的函数也需要调整,比如默认构造函数:

TVector::TVector() : _size(0), _array(nullptr) {}

push_back函数的示例调整:

void TVector::push_back(const Square& value) {
    // 分配新数组,大小为当前_size+1
    std::shared_ptr<Square[]> new_array(new Square[_size + 1]);
    
    // 拷贝旧数组元素
    for(int i = 0; i < _size; ++i){
        new_array[i] = _array[i];
    }
    
    // 添加新元素
    new_array[_size] = value;
    
    // 转移智能指针所有权,避免数组拷贝
    _array = std::move(new_array);
    _size++;
}

补充说明

  • const TVector&参数的意义:使用const修饰参数,既符合拷贝操作不修改源对象的语义,也允许从const TVector对象创建新实例,是更标准的写法。
  • 数组版shared_ptr的优势:它会自动在最后一个引用消失时释放数组内存,无需手动调用delete[],彻底避免内存泄漏风险。
  • 原malloc的问题:malloc不会调用Square的构造函数,直接对其分配的内存赋值属于未定义行为;用new或make_shared会自动调用Square的默认构造函数,再进行赋值操作,安全性更高。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.01 02:22:39