属性列表

属性(attribute)是 C++ 提供给编译器和工具的额外语义提示。它通常不改变代码的核心逻辑,而是让编译器检查得更早、优化得更明确,或让接口意图更清楚。

属性属于现代 C++ 的高阶知识:日常开发不需要大量使用,但读库代码、写公共接口和做静态检查时很有价值。

1. 基本语法

[[attribute]] void f();
[[attribute(args)]] int g();

属性可以放在函数、类型、变量、枚举、语句等位置,具体能放哪里取决于属性本身。

2. 常用标准属性

属性标准主要作用常见场景
[[nodiscard]]C++17 / C++20 扩展提醒返回值不能随意忽略错误码、结果对象、工厂函数
[[maybe_unused]]C++17标记可能未使用,避免无意义警告调试变量、平台条件编译参数
[[deprecated]]C++14标记接口已废弃旧 API 迁移
[[fallthrough]]C++17明确 switch 分支有意贯穿case 之间不写 break
[[likely]] / [[unlikely]]C++20提示分支概率性能敏感路径
[[no_unique_address]]C++20允许空成员不占额外空间泛型库、压缩空对象

3. [[nodiscard]]

[[nodiscard]] 用来提醒调用者:返回值表达了重要结果,忽略它很可能是错误。

[[nodiscard]] bool save_config(const Config& cfg);
 
void run(const Config& cfg) {
    save_config(cfg); // 编译器通常会警告:返回值被忽略
}

适合使用的情况:

  • 函数返回成功/失败状态。
  • 函数返回错误码或结果对象。
  • 工厂函数返回需要接管的对象。
  • 返回值被忽略后可能导致资源泄漏、逻辑错误或错误处理缺失。

C++20 起也可以标记类型:

struct [[nodiscard]] Result {
    bool ok;
    std::string message;
};
 
Result parse(std::string_view text);

如果确实要忽略返回值,用显式 (void) 表达意图:

(void)save_config(cfg);

4. 使用原则

  • 属性是辅助约束,不替代清晰的类型设计和错误处理。
  • 公共接口优先考虑 [[nodiscard]][[deprecated]] 这类能减少误用的属性。
  • 性能提示类属性要谨慎使用,先确认瓶颈,再给编译器提示。
  • 编译器对属性的警告强度可能不同,重要项目应配合编译选项和 CI 检查。

5. 总结

属性列表不是必背语法表。学习重点是知道:现代 C++ 可以用标准属性把“这个返回值很重要”“这个接口废弃了”“这里故意贯穿”等意图交给编译器检查。[[nodiscard]] 只是属性体系里的一个常用子集。