通用问题

  1. 实现代码的正确性和风格将如何评分?

    以下是一些指导原则:

    • 复杂的代码段应在注释中加以说明,使读者更容易理解——但不要对简单琐碎的内容过度注释。
    • 通用的、可复用的功能应拆分为辅助函数,以避免重复代码——但也不要过度拆分,例如导致执行流程难以理解。
    • 代码应使用一致的命名规范,不应包含被注释掉的代码或调试残留。
    • 请检查所有可能出错的函数的返回值,并妥善处理这些错误。抛出异常是一种处理不可恢复错误的优雅方式。
    • 避免内存错误和泄漏、严重的性能问题(例如无缘无故地分配大量内存)或不必要的复杂方法(例如使用一个复杂的数据结构,但仅比简单方法或使用 C++ 标准库中现成的方案略微高效一点)。
    • 在报告中,我们希望看到你认真地考虑了可用的实现策略(例如数据结构的选择),并能够合理解释你所做出的选择。
    • 在提交每次作业之前,请运行 cmake --build build --target format(以统一代码格式),并确保删除起始代码中包含的任何占位代码或注释。
    • 另外(可选)运行 cmake --build build --target tidy 以获取关于 C++ 编程实践的改进建议。
    你的风格评分可能还包括测试未覆盖的功能部分。

  2. 如何运行单个测试?
  3. 将环境变量 TEST_ONLY 设置为测试的确切名称。例如,如果目标测试名为 "write, close, read",则运行命令

    export TEST_ONLY="write, close, read"

    。 然后照常运行 cmake --build build --target test。此时只会运行指定的测试。你可以通过运行 unset TEST_ONLY 来恢复原始行为。

  4. 如何打印调试信息并使其与测试步骤一起整齐地显示?
  5. 包含 "debug.hh" 头文件,并使用 debug() 函数。该函数支持字符串插值。例如:

    debug( "About to pop {} bytes", len );

  6. 可以在头文件中添加 include 语句吗?
  7. 可以,但请不要更改任何类的公共接口。

  8. 如何使用 git
  9. 以下是一些学习 Git 的资源

    简要概述:Git 提交会保存代码当前状态的快照。例如,假设你破坏了一个你知道以前能正常工作的功能,但不确定是哪段代码导致了问题。如果你在功能正常时做了一次提交,就可以检出那次提交,查看一切还正常工作时的代码状态。所以,每次实现功能后都应该提交!提交步骤如下:
    首先,git add 你修改过的文件——每次提交前都需要 add。例如 git add ./src/byte_stream.*
    然后,用一条描述代码当前状态的信息提交。例如 git commit -m "All tests pass except many_writes times out."
    你可以通过运行 git status 查看修改了哪些文件。要深入了解 Git 仓库的状态,命令行工具 tig 或图形化工具 gitk 都非常有帮助。
    一个提交所有修改文件的快捷方式是 git commit -am "[提交信息]"

    实际检查:如果你想验证自己确实提交了预期的文件,以下方法可能有用。
    首先,提交后运行 git status。你应该看到 nothing to commit, working tree clean 的提示。如果有未提交的更改,你会看到:Changes not staged for commit:
    其次,在将 git bundle 复制到 rice 服务器并登录 rice 后:

    1. 运行 $ git clone [bundle name] [unbundled name]
    2. cd 进入解压后的目录。
    3. 运行 $ git log 并确认能看到你期望的提交记录。
    4. 复制起始代码提交的 commit hash。
    5. 运行 $ git diff [hash] 以确认能看到你想提交的所有更改。

  10. 如何调试?
  11. 上面关于运行单个测试的技巧以及 debug() 函数都是很好的入门方式。除此之外,gdb 是调试实验的强大工具!如果你需要复习,可以参考 CS107 指南
    使用 gdb 调试测试的步骤:

    1. 安装 gdb(在虚拟机上,sudo apt-get install gdb)。
    2. build 目录中启动 gdb,加载你想调试的测试对应的可执行文件(ls tests 可以查看可执行文件列表)。例如在 build 目录中运行:gdb tests/byte_stream_one_write
    3. 测试失败的输出会显示失败的那部分测试。要在该部分设置断点,请在测试文件中对应测试用例创建的行上设置断点。测试源代码位于 minnow/tests(而不是 minnow/build/tests)。例如,如果你在 byte_stream_one_writewrite-pop2-end 测试失败,break 83(即 write-pop2-end 测试用例创建的位置)。
    4. 你可以像往常一样使用函数名在自定义函数上设置断点。
    其他注意事项:

实验 0

  1. 如果调用者尝试以大于可用长度的 len 进行 pop,程序应该如何处理?
  2. 对于调用者尝试弹出超过流中缓冲量的情况,我们没有任何偏好,只要你合理处理且不会崩溃即可。如果你想弹出最大可用量,我们认可。如果你想抛出异常,我们也认可。
  3. 代码需要多快?
  4. 一个合理的参考标准是:如果任何测试耗时超过 2 秒,那可能值得继续探索其他表示 ByteStream 的方式。如果测试末尾的基准测试结果低于 0.1 Gbit/s(每秒 1 亿比特),这也是一个需要重新考虑设计的信号。本实验不需要复杂的数据结构,但可能仍需要一些试错才能找到合理的方案。有时候"大 O"分析可能会误导真实程序的性能评估——常数因子可能非常重要!