CodeWalk

手写std::vector: 完整的动态数组实现

作者:Yahuda · 2026-05-30 12:55

请从零实现一个简化版的MyVector(类似std::vector),包含RAII动态内存管理、push_back/pop_back/operator[]/size/capacity/reserve/resize、迭代器支持(begin/end),以及增长策略(如2倍扩容)。

回答

Yahuda

template<typename T>
class MyVector {
  T* data;
  size_t sz;
  size_t cap;
public:
  MyVector() : data(nullptr), sz(0), cap(0) {}
  
  ~MyVector() {
    for (size_t i = 0; i < sz; ++i) data[i].~T();
    std::allocator<T>{}.deallocate(data, cap);
  }
  
  void push_back(const T& val) {
    if (sz == cap) grow();
    std::allocator<T> alloc;
    alloc.construct(data + sz, val);
    ++sz;
  }
  
  void push_back(T&& val) {
    if (sz == cap) grow();
    std::allocator<T> alloc;
    alloc.construct(data + sz, std::move(val));
    ++sz;
  }
  
  void pop_back() {
    if (sz > 0) { data[--sz].~T(); }
  }
  
  T& operator[](size_t i) { return data[i]; }
  const T& operator[](size_t i) const { return data[i]; }
  size_t size() const { return sz; }
  size_t capacity() const { return cap; }
  
  void reserve(size_t new_cap) {
    if (new_cap <= cap) return;
    T* new_data = std::allocator<T>{}.allocate(new_cap);
    size_t i = 0;
    try {
      for (; i < sz; ++i) {
        std::allocator<T>{}.construct(new_data + i, std::move_if_noexcept(data[i]));
      }
    } catch (...) {
      for (size_t j = 0; j < i; ++j) new_data[j].~T();
      std::allocator<T>{}.deallocate(new_data, new_cap);
      throw;
    }
    for (size_t i = 0; i < sz; ++i) data[i].~T();
    std::allocator<T>{}.deallocate(data, cap);
    data = new_data;
    cap = new_cap;
  }
  
  void resize(size_t n, const T& val = T{}) {
    if (n < sz) {
      for (size_t i = n; i < sz; ++i) data[i].~T();
    } else if (n > sz) {
      reserve(n);
      for (size_t i = sz; i < n; ++i)
        std::allocator<T>{}.construct(data + i, val);
    }
    sz = n;
  }
  
  void grow() {
    size_t new_cap = cap == 0 ? 1 : cap * 2;  // 2倍增长
    reserve(new_cap);
  }
  
  T* begin() { return data; }
  T* end() { return data + sz; }
  const T* begin() const { return data; }
  const T* end() const { return data + sz; }
};

关键点:使用allocator分离内存分配和对象构造,保证异常安全(push_back失败不破坏原有元素)。std::move_if_noexcept在移动可能抛异常时退化为拷贝。