[[nodiscard]] 属性指南:默认情况下?仅在某些误用检测的情况下?

Ami*_*mit 2 c++ c++17 nodiscard

(我承认这个问题是基于意见的,可能是需要考虑的方法和指南。)

[[nodiscard]]作为对编译器以及随后对开发人员的警告,表明该函数的返回值很重要并且应该使用或捕获。

什么是更好的做法(在早期阶段检测可能的错误):将[[nodiscard]]属性应用于返回值的任何成员函数(特殊情况除外)?...或者仅将其应用于必要的成员函数(例如:返回内存分配的成员函数)?

Jan*_*tke 5

何时申请[[nodiscard]]是有意见的。

最小方法

简单的方法是仅在函数无法使用且结果被丢弃时以及用户可能在没有该属性的情况下误用它时才应用它。这就是 C++ 标准库的作用。例如,std::vector::empty()被标记是[[nodiscard]]因为它可能意味着:

  • 清空向量
  • 返回向量是否为空

举另一个例子, 被std::launder标记是[[nodiscard]]因为人们通常认为它以某种方式改变了指针,并且他们不需要使用结果。[[nodiscard]]仅在标准中使用以防止此类误解和很可能发生的错误。

最大逼近

有效的方法[[nodiscard]]是在函数无法正确使用并丢弃结果时应用。例如,std::max如果您丢弃结果,则毫无意义,并且标准库实现可以自由地实现它[[nodiscard]]std::vector::size()也可以按照这个标准来制作[[nodiscard]]。事实上,大多数非 void 函数可能是(1)

Clang-Tidy 方法

您还可以坚持 clang-tidymodernize-use-nodiscard规则,该规则建议[[nodiscard]]满足以下所有条件:

  • 没有[[nodiscard]], [[noreturn]], __attribute__((warn_unused_result)),[[clang::warn_unused_result]]也没有[[gcc::warn_unused_result]]属性,
  • 非空返回类型,
  • 非模板返回类型,
  • 常量成员函数,
  • 非变量函数,
  • 没有非常量参考参数,
  • 没有指针参数,
  • 没有模板参数,
  • 没有模板函数参数,
  • 不是具有可变成员变量的类的成员,
  • 没有 Lambda,
  • 没有转换功能。

这显然是一个很长的清单,而且相当悲观,但它是一个不错的起点,并且可以自动化。

结论

您必须自己决定选择哪种方法。没有官方指南(2)。如果您不关心[[nodiscard]]大量函数所增加的冗长性,那么使用最大方法是完全可以的。正确[[nodiscard]]使用的属性越多,能够防止的错误就越多。


(1) 大多数,但不是全部。例如,operator<<流插入不应该重载,[[nodiscard]]因为丢弃结果流是常见的做法。这同样适用于operator=过载。

(2) CppCoreGuidelines 还没有决定推荐。人们一致认为应该有一些指导方针[[nodiscard]],但讨论却陷入了具体细节,人们对这个主题失去了兴趣。