为什么C++20中的std::move不是[[nodiscard]]?

52
我最近了解到C++17中的[[nodiscard]],据我所知它是一项新功能(设计合同?),它强制你使用返回值。这对于像std::launder这样备受争议的函数来说是有意义的(自C++20以来变成nodiscard),但我想知道为什么std::move在C++17/20中没有被定义为这样的特性。你知道一个好的原因吗?还是因为C++20还没有确定下来?

9
当你不使用它时,绝对不会发生任何坏事(或者根本没有事情发生)。 - Sebastian Redl
6
同样地,没有任何有用的事情发生。这与编写空语句相同,因此 [[nodiscard]] 可以帮助诊断错误。当忽略 vector::empty() 时也不会发生任何坏事,但出于明显的原因,它被标记为 [[nodiscard]] - Vittorio Romeo
6
这听起来是一个很好的理由去将其标记为[[nodiscard]]: “嘿,你做了完全无意义的事情。你是想做其他的事情吗?” - Barry
4
std::move 并不会移动对象。通过 std::move 传递一个对象并忽略结果将完全没有任何效果。 - tkausl
2
@bbalchev,“std::move”的功能只是返回对象的右值引用,以便在引用被这样使用的情况下,该对象随后可以被移动。 - Sebastian Redl
显示剩余8条评论
2个回答

53
自VS 2017 15.6版本以来,MSVC标准库团队已经添加了数千个[[nodiscard]]实例,并且使用它们的效果非常好(在发现大量错误的同时没有收到用户投诉)。他们所描述的标准大致如下:
  1. 纯观察者,例如vector::size()vector::empty,甚至还有std::count_if()
  2. 获取原始资源的事物,例如allocate()
  3. 返回值被忽略极有可能导致不正确代码的函数,例如std::remove()

根据这些标准,MSVC将std::move()std::forward()也标记为[[nodiscard]]

虽然在标准中它还没有正式注释,但它似乎为用户提供了明显的好处,只需编写这样一篇论文,以标记所有适当的[[nodiscard]](MSVC中有数千个实例),然后应用即可。这并不是很复杂的工作,但需要处理大量内容。与此同时,也许可以督促你喜欢的标准库供应商去标记大量的[[nodiscard]]呢?


32
据我所知,P0600R1 是唯一一个被应用到 C++20 的向标准库添加 [[nodiscard]] 的提案。从该文档中可以得知:

我们建议采取保守的方法:

[...]

当以下情况出现时,不应添加:

  • [...]
  • 未使用返回值可能没有意义,但不会产生错误且通常不是错误
  • [...]

因此,如果满足以下条件,[[nodiscard]] 不应被视为代码质量不佳:

  • [...]
  • 即使没有返回值也不会有副作用
因此,原因在于标准库采用了保守的方法,而目前还没有提出更加激进的方法。

7
我不确定。在我的看法中,不使用 std::move 的返回值总是一种错误,因此根据您的引用,应该将其标记为 nodiscard: 这要么意味着用户忘记了使用返回值,要么意味着调用是不必要的,因为它没有任何效果。 - Konrad Rudolph
1
@KonradRudolph:显然没有人向委员会展示过在std::move()缺少nodiscard时会导致实际错误的常见情况。考虑在C++标准讨论邮件列表中提出这个问题。 - einpoklum
1
@einpoklum:我猜像其他人一样,我认为这个问题不紧急到值得委员会在上面浪费时间(已经有太多新建议了)。我只是想说,缺少[[nodiscard]]可能是一种无意的疏忽,而不是受到此答案中引用的语录的有意决定所驱动。 - Konrad Rudolph

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接