c++中如何实现一个简单的动态数组类_c++封装vector功能步骤【详解】

10次阅读

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

c++中如何实现一个简单的动态数组类_c++封装vector功能步骤【详解】

为什么别直接封装 std::vector

你写一个叫 MyVector 的类,内部用 std::vector 做成员,这不算“实现动态数组”——这只是包装。真正想练手或理解底层机制,得自己管理内存:new/delete[]、容量扩容逻辑、拷贝/移动语义。标准库std::vector 已经高度优化,封装它没有教学价值,反而掩盖关键细节。

核心三步:内存分配 + 容量增长 + 异常安全

一个最小可用的动态数组类必须处理好这三点。漏掉异常安全,push_backnew 失败时可能造成内存泄漏或对象状态不一致。

  • 初始容量设为 1 或 2,避免频繁扩容;后续按 1.5 倍或 2 倍增长(std::vector 通常用 1.5)
  • 每次扩容必须: new 新内存 → 逐个 std::construct_atc++20)或 placement new 拷贝旧元素 → 析构旧元素 → delete[] 旧内存
  • 所有可能抛异常的操作(如构造元素)必须放在 try/catch,否则扩容中途失败会导致资源泄露

MyVector 必须实现的接口和陷阱

只暴露 push_backsizecapacityoperator[]析构函数,已足够体现原理。但要注意:

  • operator[] 不做越界检查(像 std::vector::operator[]),但 at() 如果加了就必须 throw std::out_of_range
  • push_back 参数该用 const T& 还是 T&&?正确做法是重载两个,再加模板版本支持完美转发:
    template void push_back(U&& val);
  • 析构函数里必须对每个已构造元素显式调用析构函数,不能只 delete[] data_ —— 否则类类型元素的析构函数不会执行

一个极简但正确的 MyVector 片段(C++17)

以下代码能通过基本测试,且不依赖 std::vector

立即学习C++免费学习笔记(深入)”;

template class 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;手写版本最容易出错的是析构顺序、异常路径遗漏、以及未处理 Tconst引用类型的情况——这些边界在教学代码里常被忽略。

text=ZqhQzanResources