Step 08

访问、迭代器与异常安全

粘贴到作业纸 student/mini_vector/vector.hpp 底部不需要仓库,起步页已有全部工程文件

把本页「可粘贴代码」整段(从 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*'