Step 08
访问、迭代器与异常安全
把本页「可粘贴代码」整段(从 template 到函数结尾)替换作业纸里对应的 TODO。不要贴进 class 体内。本步搜索 TODO(step 08),替换: at、at const。参考答案在 参考答案页;编译问题见 常见问题。
Step 08 — 访问、迭代器、异常安全
到这一步容器已经能用了。补上 at,并确认几条异常安全不变量。
作业纸里已经有的(不要再贴进 class)
operator[] / front / back、全部迭代器、operator== / operator!= 在 class 体内已经实现。
operator[]/front/back越界是 UB,不要检查。需要检查时用at。begin是data_,end是data_ + size_(不是+ capacity_)。operator==只比较size和每个元素,不比较 capacity。reserve(32)过的{1,2}和刚刚push_back出来的{1,2}应当相等。
在作业纸里改哪里
搜索 TODO(step 08),只有两个 at。
可粘贴代码
template <typename T, typename Allocator>
typename Vector<T, Allocator>::reference
Vector<T, Allocator>::at(size_type index) {
if (index >= size_) {
throw std::out_of_range("mini::Vector::at");
}
return data_[index];
}template <typename T, typename Allocator>
typename Vector<T, Allocator>::const_reference
Vector<T, Allocator>::at(size_type index) const {
if (index >= size_) {
throw std::out_of_range("mini::Vector::at");
}
return data_[index];
}异常安全清单(对照实现再看一遍)
| 操作 | 保证 | 做法 |
|---|---|---|
emplace_back 有空槽 |
强 | construct 抛则不 ++size_ |
emplace_back 扩容 |
强(T 可拷或移动 noexcept) | 新缓冲失败则整块丢弃,旧缓冲不动 |
reserve |
强(同上) | 先 relocate 成功再切换指针 |
resize 缩小 |
无异常 | 只 destroy |
resize 放大 |
强 | 先在独立缓冲造好,再切换指针 |
| 拷贝赋值 | 强 | copy-and-swap |
析构 / clear / pop_back |
noexcept | 假定 T 析构不抛 |
ThrowOnCopy / ThrowOnMove 测试就是在检查这张表。
常见漏测场景(测试里都有)
- Move-only:
Vector<unique_ptr<string>>、Vector<MoveOnly>,不能走拷贝路径。 - 无默认构造:
resize(n)从重载集消失,emplace_back(int)和resize(n, value)仍可用。 - 自定义分配器:
construct/destroy/allocate/deallocate次数能对上,析构后 bytes 归零。 - 自引用
push_back(v[0]):扩容顺序。 resize(n, v[0]):先拷栈上临时变量。
作业纸填完了吗?
在 student/mini_vector/vector.hpp 里搜索 TODO(。如果还有命中,回到对应章节把整段类外定义贴上。常见漏贴:
uninitialized_copy_n少了一层template <typename InputIt>- 构造函数类外定义里写了
= Allocator()(默认实参只能写在声明上) - 把示意代码贴进了
class体内,出现 redefinition
验收(这一步之后应该全绿)
cmake --build build
ctest --test-dir build --output-on-failure如果之前配置过,确认学生开关还在:
cmake -B build -DMINI_VECTOR_USE_STUDENT=ON -DCMAKE_CXX_COMPILER=g++
cmake --build build
ctest --test-dir build --output-on-failure卡住超过二十分钟,再打开网站「参考答案」页,对照同一个函数。不要整文件覆盖作业纸,否则看不出自己漏在哪。
本步验收
cmake --build build
./build/vector_tests --gtest_filter='Step08*:ExceptionSafety*:MoveOnly*'