c++的[[nodiscard]]属性有什么用? (强制检查返回值)

不能直接阻止,但能触发编译器警告;它提示返回值有意义、不应被忽略,是否报错取决于编译器及警告设置。

[[nodiscard]] 能阻止调用者忽略返回值吗?

不能直接阻止,但能触发编译器警告(或错误,取决于编译选项)。它只是给编译器一个提示:这个函数/类型/构造函数的返回值“有意义”,不该被丢弃。是否报错,取决于你用的编译器和警告级别设置。

哪些地方可以加 [[nodiscard]]?

支持位置包括:函数声明、枚举定义、类/结构体定义、构造函数(C++20 起)、typedef / alias 声明(C++23)。最常见的是加在函数上。

  • [[nodiscard]] int parse_int(const std::string& s); —— 提示调用者检查解析是否成功
  • [[nodiscard]] std::unique_ptr create_widget(); —— 防止资源泄漏(忘了接管指针)
  • [[nodiscard]] bool try_lock(); —— 忽略锁是否获取成功,容易引发竞态

不加 [[nodiscard]] 会出什么问题?

典型问题是逻辑漏洞难以发现。比如:

std::vector v = {1, 2, 3};
v.push_back(4); // 返回 void,没问题
v.insert(v.begin(), 5); // 返回 iterator,但没人用 —— 暂时无害
auto res = std::binary_search(v.begin(), v.end(), 7); // 返回 bool,但写成 std::binary_search(...);就丢了结果

更危险的是:

  • std::fopen("data.txt", "r") 忽略返回值 → nullptr 指针后续解引用崩溃
  • std::fclose(fp) 忽略返回值 → 不知道关闭是否失败,可能丢数据
  • 自定义的 [[nodiscard]] Result parse_json(...) 被静默丢弃 → 错误未处理

怎么让 [[nodiscard]] 真正起作用?

必须配合编译器警告开关:

  • GCC / Clang:-Wnarrowing -Wreturn-type -Wignored-attributes(部分版本需 -Werror=unused-result 或启用 -Wnodiscard
  • MSVC:/wd4834(禁用该警告)或默认已启用 C++17+ 的 [[nodiscard]] 检查
  • CMake 中建议加:set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Werror=unused-result -Wno-unused-parameter")

注意:如果函数返回 void[[nodiscard]] 会被忽略;如果返回值是字面量(如 42)或临时对象且没绑定到引用,某些编译器也可能不警告。

最容易被忽略的是:它不检查“语义上是否该用”,只检查“语法上是否写了”。比如 (void)foo();foo(); 在有重载且某重载返回 void

时,也可能绕过检查。别把它当成银弹,而是配合代码审查和单元测试一起用。