Step 01
骨架与内存模型
Step 01 — 骨架与内存模型
std::vector 不是“一块已经构造好的数组”,而是:
data_ → [ 已构造的 T ][ 已构造的 T ][ 未初始化内存 ][ 未初始化内存 ]
|← size_ →|← capacity_ - size_ →|
size_:已经调用过构造函数的元素个数。push_back/emplace_back让它 +1,pop_back/resize缩小让它减少。capacity_:allocate向分配器要来的槽位数。reserve只动它,不动size_。data_:指向这块内存的起点。capacity_ == 0时它是nullptr。
把这两件事混在一起,是手搓 vector 时最常见的 bug:在未初始化的槽位上读 T,或者 reserve 时去默认构造 T(于是不支持“没有默认构造的 T”)。
这一步不用改作业纸
起步页保存的 student/mini_vector/vector.hpp 已经包含 三个字段、empty / size / capacity / data,以及默认构造。不要把下面的示意再贴进 class 体内,否则会重复定义、编译失败。
作业纸现在长这样(只需确认,不要复制):
T* data_{nullptr};
size_type size_{0};
size_type capacity_{0};
[[no_unique_address]] Allocator alloc_{};
Vector() noexcept(std::is_nothrow_default_constructible_v<Allocator>) = default;
explicit Vector(const Allocator& alloc) noexcept : alloc_(alloc) {}
[[nodiscard]] bool empty() const noexcept { return size_ == 0; }
size_type size() const noexcept { return size_; }
size_type capacity() const noexcept { return capacity_; }
T* data() noexcept { return data_; }
const T* data() const noexcept { return data_; }默认构造之后:empty() == true,size() == 0,capacity() == 0,data() == nullptr。还没向操作系统要过任何内存。
Vector(n)、Vector(n, value)、initializer_list 构造函数先留着 TODO,Step 06 再填。现在填它们会调用还没写的 allocate_n。
为什么 iterator 直接用 T*
教学实现够用了:vector 的迭代器本就是随机访问,指针满足 begin() + n、end() - begin() 这些接口。标准库用 class iterator 是为了调试时抓越界、以及 fancy pointer。下一步会接到 allocator,但存储仍按 T* 处理(用 std::to_address 把分配器返回的 pointer 转成裸指针)。
作业纸里 begin / end / operator[] 也已经写好。空 vector 时 data_ 是 nullptr,begin() == end() == nullptr,范围 for 不会解引用。
怎么粘贴(后面每步都一样)
作业纸分两截:
- 上半
class Vector { ... };:只有声明。除了 Step 07 要给拷贝操作补requires(作业纸已写好)之外,不要往 class 里面塞函数体。 - 下半
template <typename T, typename Allocator> ... Vector<T, Allocator>::foo(...):每个 TODO 对应一个完整函数。用教学站给出的整段(从template到函数最后的})替换那个函数,不要只贴函数体、也不要漏掉template头。
搜索标记:TODO(step 02)、TODO(step 03) ……
验收
先按起步页配好工程(学生开关打开),然后:
cmake --build build
./build/vector_tests --gtest_filter='Step01.EmptyVectorHasZeroSizeAndCapacity'这一条现在就该绿。CountConstructor、Vector(n) 那些要等到 Step 03 / 06。
本步验收
cmake --build build
./build/vector_tests --gtest_filter='Step01*'