本文嘗試從零實現一個與 std::vector 介面相容的容器,核心要求:
vector 本質是動態陣列,維護三個關鍵指標:
T* buf:指向堆上連續記憶體塊size_t size_:當前元素個數size_t capacity_:已分配容量當 size_ == capacity_ 時觸發擴容,典型增長因子為 1.5~2.0(本實現採用 2 倍):
void newCapacity(size_t newCap) {
T* newBuf = static_cast<T*>(::operator new(newCap * sizeof(T)));
// 移動構造/拷貝構造現有元素
for (size_t i = 0; i < size_; ++i)
new (newBuf + i) T(std::move(buf[i])); // C++11 move 語義
// 銷毀舊元素並釋放記憶體
for (size_t i = 0; i < size_; ++i) buf[i].~T();
::operator delete(buf);
buf = newBuf;
capacity_ = newCap;
}
關鍵細節:使用 operator new 原始分配、placement new 就地構造、顯式呼叫解構函式,避免 new T[n] 強制要求預設構造函式。
insert(iterator, const T&)void insert(const_iterator iter, const T& t) {
size_t index = iter - begin(); // 迭代器差值得索引
if (index < size_) {
if (size_ == capacity_) newCapacity(calculateCapacity());
// 向後搬移 [index, size_) 區間
std::memmove(buf + index + 1, buf + index,
(size_ - index) * sizeof(T));
buf[index] = t; // 拷貝賦值
++size_;
}
}
效能考量:
memmove 而非逐元素搬移,針對 TriviallyCopyable 型別可優化為 memcpy。erase(iterator) 與 clear()iterator erase(const_iterator iter) {
size_t index = iter - begin();
if (index < size_ && size_ > 0) {
// 向前搬移 (index, size_) 區間
std::memmove(buf + index, buf + index + 1,
(size_ - index) * sizeof(T));
buf[--size_] = T(); // 銷毀最後元素,置為預設值
}
return iterator(iter);
}
void clear() {
while (size_ > 0) erase(begin()); // 僅銷毀元素,不釋放記憶體
}
設計哲學:clear() 保留容量,避免頻繁增減容造成記憶體碎片;記憶體釋放留給析構函式或 shrink_to_fit()。
+、-、[]、< 等運算,本質封裝 T*。begin() = buf,end() = buf + size_。const_iterator 透過 const T* 實現唯讀視圖。| 分類 | 介面 |
|---|---|
| 容量 | size(), capacity(), empty(), reserve(), shrink_to_fit() |
| 元素存取 | operator[], at(), front(), back(), data() |
| 修改器 | push_back(), pop_back(), insert(), erase(), clear(), resize(), swap() |
| 迭代器 | begin(), end(), rbegin(), rend(), cbegin(), cend() |
std::move 避免不必要拷貝。shrink_to_fit() 為非強制請求,實現可選擇忽略。std::aligned_alloc 或 alignas 處理過度對齊型別。