直接封装std::vector不算实现动态数组,真正练手需自己管理内存、扩容逻辑和异常安全;核心是内存分配、容量增长、异常安全三步,且须正确处理构造/析构与完美转发。

为什么别直接封装 std::vector?
你写一个叫 MyVector 的类,内部用 std::vector 做成员,这不算“实现动态数组”——这只是包装。真正想练手或理解底层机制,得自己管理内存:new/delete[]、容量扩容逻辑、拷贝/移动语义。标准库的 std::vector 已经高度优化,封装它没有教学价值,反而掩盖关键细节。
核心三步:内存分配 + 容量增长 + 异常安全
一个最小可用的动态数组类必须处理好这三点。漏掉异常安全,push_back 在 new 失败时可能造成内存泄漏或对象状态不一致。
-
初始容量设为 1 或 2,避免频繁扩容;后续按 1.5 倍或 2 倍增长(
std::vector通常用 1.5) -
每次扩容必须:
new新内存 → 逐个std::construct_at(C++20)或placement new拷贝旧元素 → 析构旧元素 →delete[]旧内存 - 所有可能抛异常的操作(如构造元素)必须放在 try/catch 内,否则扩容中途失败会导致资源泄露
MyVector 必须实现的接口和陷阱
只暴露 push_back、size、capacity、operator[] 和析构函数,已足够体现原理。但要注意:
-
operator[]不做越界检查(像std::vector::operator[]),但at()如果加了就必须 throwstd::out_of_range -
push_back参数该用const T&还是T&&?正确做法是重载两个,再加模板版本支持完美转发:template
void push_back(U&& val); - 析构函数里必须对每个已构造元素显式调用析构函数,不能只
delete[] data_—— 否则类类型元素的析构函数不会执行
一个极简但正确的 MyVector 片段(C++17)
以下代码能通过基本测试,且不依赖 std::vector:
立即学习“C++免费学习笔记(深入)”;
templateclass MyVector { T* data_ = nullptr; size_t size_ = 0; size_t capacity_ = 0; public: ~MyVector() { for (sizet i = 0; i < size; ++i) { data[i].~T(); } delete[] data; }
void push_back(const T& val) { if (size_ >= capacity_) { size_t new_cap = capacity_ == 0 ? 1 : capacity_ * 2; T* new_data = new T[new_cap]; for (size_t i = 0; i < size_; ++i) { new_data[i] = std::move(data_[i]); data_[i].~T(); } delete[] data_; data_ = new_data; capacity_ = new_cap; } new (&data_[size_]) T(val); ++size_; } T& operator[](size_t i) { return data_[i]; } size_t size() const { return size_; } size_t capacity() const { return capacity_; }};
注意:真实项目中仍应优先用
std::vector;手写版本最容易出错的是析构顺序、异常路径遗漏、以及未处理T是const或引用类型的情况——这些边界在教学代码里常被忽略。











