如何改写C++ SortedList拷贝构造函数避免使用多个new运算符?
问题根源分析
你尝试的T* new_element=& T(*(list.data[i]));写法本质是构造了一个临时T对象,临时对象的生命周期仅存在于当前表达式,表达式结束后立即销毁,此时你取到的地址是悬空指针,因此编译器会直接报taking address of temporary错误,该写法完全不可行。
另外你对“多余的new”的理解存在偏差:你当前的data成员是T**类型(存储T指针的数组),要做深拷贝的话,每个T对象本身就需要独立分配堆内存,你原来写的new T(*(list.data[i]))是实现深拷贝的必要操作,本身不是多余的。你认为的“不符合规范”,实际是裸指针手动管理内存带来的异常安全、内存泄漏风险,而非new操作本身多余。
解决方案
根据你的需求(不依赖T()默认构造、符合编码规范、减少不必要的内存分配),给出两种可选方案:
方案1:保留现有存储结构,用智能指针替代裸指针(改动最小)
将data的类型从裸二级指针改为std::unique_ptr<std::unique_ptr<T>[]>,利用RAII机制自动管理内存,不需要手动写delete,也完全避免内存泄漏风险,同时不需要修改核心逻辑:
template <class T> SortedList<T>::SortedList(const SortedList<T>& list): data(std::make_unique<std::unique_ptr<T>[]>(list.max_size)) ,size(list.size) ,max_size(list.max_size) { for (int i = 0; i < size; i++) { data[i] = std::make_unique<T>(*list.data[i]); } }
该方案依然保留每个T对象的独立内存分配,仅优化了内存管理方式,不需要依赖T的默认构造函数。
方案2:优化存储结构,去掉多余的指针间接层(推荐)
你当前用T**存储相当于多了一层不必要的指针跳转,改为直接存储T的一维数组即可,全程仅需要一次内存分配,完全去掉循环内的多个new操作。要避免调用T的默认构造,可以用std::allocator分配原始内存再手动构造对象:
首先修改类成员定义:
// 类内成员声明 T* data; std::allocator<T> alloc; size_t size; size_t max_size;
拷贝构造实现:
template <class T> SortedList<T>::SortedList(const SortedList<T>& list): data(alloc.allocate(list.max_size)) ,size(list.size) ,max_size(list.max_size) { for (int i = 0; i < size; i++) { std::construct_at(data + i, *list.data[i]); } }
配套的析构函数实现:
template <class T> SortedList<T>::~SortedList() { for (int i = 0; i < size; i++) { std::destroy_at(data + i); } alloc.deallocate(data, max_size); }
该方案全程仅调用一次内存分配,没有循环内的多余new操作,全程只调用T的拷贝构造函数,完全不依赖默认构造T(),性能和规范性都更好。
如果不想手动管理分配器,直接将data改为std::vector<T>即可,编译器自动生成的拷贝构造就能满足所有需求,不需要你手动写任何内存管理代码。
内容的提问来源于stack exchange,提问作者Raea6789

