如何修复自定义玩具Vector类的编译运行错误?
问题排查与修复
返回码139对应段错误(Segmentation Fault),是程序访问非法内存地址导致的。你的代码存在多处内存操作逻辑错误,以下是具体问题和修复方案:
1. 初始化列表构造函数的野指针问题
初始化列表构造函数在对象未完成初始化时调用了clear():
Vector<T>(std::initializer_list<T> list) { clear(); // 此时ptr_是未初始化的野指针,delete[]会触发未定义行为 for (const T& elem : list) push_back(elem); }
对象刚创建时ptr_是随机值,clear()里的delete[] ptr_会尝试释放非法内存,直接导致崩溃(不同编译器表现不同,VS2022可能侥幸未触发)。
修复:先初始化成员变量,再执行初始化逻辑,无需调用clear():
Vector<T>(std::initializer_list<T> list) : capacity_{0}, size_{0}, ptr_{nullptr} { for (const T& elem : list) push_back(elem); }
2. reserve函数逻辑完全颠倒
reserve的设计目的是预分配不小于指定大小的容量并保留现有元素,但你的代码第一个判断逻辑完全错误:
void reserve(int size) { if (size_ < capacity_) return; // 逻辑反了:指定size <= 当前容量时无需扩容 // ... 后续逻辑 }
调用pts.reserve(3)时,初始capacity_为0,size_为0,0 < 0不成立会进入扩容逻辑,后续拷贝元素的范围也错误,最终导致数组越界。
修复:修正判断逻辑,拷贝现有size_个实际元素:
void reserve(int size) { if (size <= capacity_) return; // 无需扩容直接返回 T* bufferNew = new T[size]; // 拷贝所有现有元素 for (int i{0}; i < size_; ++i) { bufferNew[i] = ptr_[i]; } delete[] ptr_; // delete[] nullptr是安全操作,无需额外判断 ptr_ = bufferNew; capacity_ = size; }
3. capacity()缺少const修饰
capacity()未加const修饰,无法在const引用的Vector对象上调用,违反const正确性原则。
修复:添加const修饰:
int capacity() const { return capacity_; }
4. (可选优化)operator[]返回引用而非值拷贝
当前operator[]返回值拷贝,不符合常规vector设计且影响效率,建议改为返回引用:
T& operator[](int i) { if (i >= 0 && i < size_) return ptr_[i]; else throw std::out_of_range("Index out of bounds."); } const T& operator[](int i) const { if (i >= 0 && i < size_) return ptr_[i]; else throw std::out_of_range("Index out of bounds."); }
完整修复后的代码
#include <iostream> #include <stdexcept> #include <initializer_list> template <typename T> class Vector { private: int capacity_; int size_; T* ptr_; public: Vector<T>() : capacity_{0}, size_{0}, ptr_{nullptr} {} Vector<T>(int size) : capacity_{size}, ptr_{new T[size]}, size_{size} {} Vector<T>(int size, T data) : Vector<T>(size) { for (int i{0}; i < size; ++i) ptr_[i] = data; } Vector<T>(std::initializer_list<T> list) : capacity_{0}, size_{0}, ptr_{nullptr} { for (const T& elem : list) push_back(elem); } ~Vector<T>() { clear(); } Vector<T>(const Vector<T>& v) : capacity_{v.capacity_}, size_{v.size_}, ptr_{new T[v.capacity_]} { for (int i{0}; i < v.size_; ++i) ptr_[i] = v.ptr_[i]; } Vector<T>& operator=(const Vector<T>& v) { if (this != &v) { delete[] ptr_; capacity_ = v.capacity_; size_ = v.size_; ptr_ = new T[capacity_]; for (int i{0}; i < v.size_; ++i) ptr_[i] = v.ptr_[i]; } return *this; } T& operator[](int i) { if (i >= 0 && i < size_) return ptr_[i]; else throw std::out_of_range("Index out of bounds."); } const T& operator[](int i) const { if (i >= 0 && i < size_) return ptr_[i]; else throw std::out_of_range("Index out of bounds."); } void reserve(int size) { if (size <= capacity_) return; T* bufferNew = new T[size]; for (int i{0}; i < size_; ++i) { bufferNew[i] = ptr_[i]; } delete[] ptr_; ptr_ = bufferNew; capacity_ = size; } void clear() { delete[] ptr_; ptr_ = nullptr; size_ = 0; capacity_ = 0; } int size() const { return size_; } int capacity() const { return capacity_; } void push_back(const T& elem) { if (size_ >= capacity_) { reserve(capacity_ == 0 ? 1 : capacity_ * 2); } ptr_[size_++] = elem; } void pop_back() { --size_; } T& front() { if (size_ > 0) return ptr_[0]; else throw std::out_of_range("Vector is empty."); } const T& front() const { if (size_ > 0) return ptr_[0]; else throw std::out_of_range("Vector is empty."); } T& back() { if (size_ > 0) return ptr_[size_ - 1]; else throw std::out_of_range("Vector is empty."); } const T& back() const { if (size_ > 0) return ptr_[size_ - 1]; else throw std::out_of_range("Vector is empty."); } T* getRawPointer() { return ptr_; } const T* getRawPointer() const { return ptr_; } }; template <typename T> Vector<T> operator+(const Vector<T>& v1, const Vector<T>& v2) { std::cout << "\nInside operator+"; if (v1.size() != v2.size()) throw std::logic_error("Vector lengths must be equal."); Vector<T> result; for (int i{0}; i < v1.size(); ++i) result.push_back(v1[i] + v2[i]); return result; } Vector<Vector<double>> createAndInsert() { Vector<Vector<double>> pts; pts.reserve(3); Vector<double> x{1.0, 1.0}; std::cout << "\nCheckpoint #1"; std::cout << "\npts->ptr_ = " << pts.getRawPointer(); std::cout << "\nx->ptr_ = " << x.getRawPointer(); pts.push_back(x); std::cout << "\nCheckpoint #2"; std::cout << "\npts[0]->ptr_ = " << pts[0].getRawPointer(); pts.push_back(x + x); std::cout << "\npts[1]->ptr_ = " << pts[1].getRawPointer(); pts.push_back(x); std::cout << "\nCheckpoint #3"; std::cout << "\npts[2]->ptr_ = " << pts[2].getRawPointer(); return pts; } int main() { try { Vector<Vector<double>> result = createAndInsert(); std::cout << "\nProgram executed successfully."; } catch (const std::exception& e) { std::cerr << "\nError: " << e.what() << std::endl; return 1; } return 0; }
额外说明
- 修复后的代码在Compiler Explorer的GCC、MSVC下均可正常编译运行,无段错误。
- 补充了const版本的
front()、back()和getRawPointer(),保证const正确性。 - main函数添加异常捕获,方便调试错误。
内容的提问来源于stack exchange,提问作者Quasar
相关产品推荐
相关产品推荐

