为何调用vec.push_back(v)时会触发析构函数?
仿STL Vector嵌套push_back后元素被销毁的问题分析与修复
你的Vector类存在几个核心问题,直接导致了嵌套push_back后元素被销毁的现象,下面逐个拆解并给出修复方案:
核心问题1:缺失深拷贝的拷贝构造与赋值运算符
C++编译器会为类生成默认的拷贝构造函数和赋值运算符,但这些默认实现是浅拷贝——只复制成员变量的表面值,比如你的arr指针。当你调用vec.push_back(v)时:
- 如果你用的是传值的
push_back(Vector val)重载,参数val是v的浅拷贝副本,它和v共享同一块arr内存。 - 函数执行完毕后,临时参数
val会被析构,调用~Vector()释放arr内存,此时原v的arr就变成了野指针,后续访问就会表现为"元素被销毁"。 - 即使你用引用版本的
push_back,当Vector内部Realloc扩容时,循环里的arr[i] = temp[i]也是浅拷贝,会导致多个Vector对象共享内存,析构时重复释放。
核心问题2:冗余的push_back重载
你额外写了push_back(Vector val)的重载,完全没必要——模板类的T已经可以处理Vector<int>类型,这个重载反而强制传值,引发不必要的拷贝和临时对象析构,加重了问题。
其他次要问题
isEmpty逻辑错误:if(capacity && size)会在size为0(已有一个元素)时返回true,判断为空,明显不符合预期。- 析构函数输出误导:打印的是
capacity却标注为"size",容易混淆调试信息。 at函数返回0不合理:对于非数值类型,返回0会编译错误,应该返回T{}默认构造值。
修复后的完整代码
#include <iostream> using namespace std; template <typename T, int cap=1> class Vector { private: T* arr{}; int capacity = cap; int size = -1; // size表示最后一个元素的索引,sizeOf()返回元素总数size+1 public: // 默认构造函数 Vector() { arr = new T[capacity]{}; } // 拷贝构造:深拷贝,确保每个Vector拥有独立内存 Vector(const Vector& other) { capacity = other.capacity; size = other.size; arr = new T[capacity]{}; for (int i = 0; i <= size; ++i) { arr[i] = other.arr[i]; } } // 赋值运算符:用拷贝交换范式实现深拷贝,简洁且安全 Vector& operator=(Vector other) { swap(arr, other.arr); swap(capacity, other.capacity); swap(size, other.size); return *this; } // 析构函数:释放内存并标记指针为空 ~Vector() { cout << "Deleting Vector | capacity: " << capacity << ", element count: " << sizeOf() << '\n'; delete[] arr; arr = nullptr; } // 判断是否为空的正确逻辑 bool isEmpty() const { return size == -1; } // 扩容函数:深拷贝原元素到新内存 void Realloc() { cout << "Realloc: capacity from " << capacity << " → " << 2*capacity << '\n'; T* temp = arr; capacity *= 2; arr = new T[capacity]{}; for (int i = 0; i <= size; ++i) { arr[i] = temp[i]; // 调用T的赋值运算符,嵌套时自动深拷贝 } delete[] temp; temp = nullptr; } // 返回元素总数 int sizeOf() const { return size + 1; } // 统一的push_back:用const引用避免不必要拷贝,支持临时对象 void push_back(const T& val) { ++size; if (size < capacity) { arr[size] = val; return; } Realloc(); arr[size] = val; } // 删除指定位置元素 void erase(int pointer) { if (pointer < 0 || pointer > size) { return; } for (; pointer < size; ++pointer) { arr[pointer] = arr[pointer + 1]; } --size; } // 返回当前容量 int capacityOf() const { return capacity; } // 安全访问元素,越界返回默认值 T at(int val) const { if (val >= 0 && val <= size) { return arr[val]; } return T{}; } // 非const下标访问 T& operator[] (int val) { return arr[val]; } // const下标访问,支持const对象 const T& operator[] (int val) const { return arr[val]; } };
测试用main函数
int main() { Vector<int> v; Vector<Vector<int>> vec; v.push_back(1); v.push_back(2); v.push_back(3); v.push_back(4); v.push_back(5); v.push_back(6); cout << "v's element count: " << v.sizeOf() << "\n"; vec.push_back(v); // 验证嵌套Vector的元素未被销毁 cout << "\nNested vector element count: " << vec[0].sizeOf() << "\n"; cout << "First element of nested vector: " << vec[0][0] << "\n"; cout << "Last element of nested vector: " << vec[0][5] << "\n"; }
修复关键点说明
- 深拷贝实现:拷贝构造和赋值运算符确保每个Vector对象拥有独立的内存空间,拷贝时复制所有元素,彻底避免浅拷贝导致的内存共享问题。
- 统一push_back:删除冗余重载,改用
const T&参数,既避免不必要的拷贝,又支持传入临时对象。 - 扩容逻辑优化:Realloc中的拷贝操作现在会调用T的赋值运算符,对于嵌套的Vector
来说,自动执行深拷贝。 - 逻辑修正:修复isEmpty、析构函数输出等细节问题,提升代码的正确性和可调试性。
内容的提问来源于stack exchange,提问作者QCM
相关产品推荐
相关产品推荐

