手写std::vector: 完整的动态数组实现
请从零实现一个简化版的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在移动可能抛异常时退化为拷贝。