我想返回布尔变量/数据成员的当前值并在一个语句中将其设置为 false。

这与性能无关,而是由于我在代码中的几个地方使用了它,因此语句更少,输入错误的几率也更少(我已经有一个输入错误,导致我清除了与返回的变量不同的变量)。

我用它来获取和清除布尔事件标志,例如已按下的按钮。

我的程序中有几个地方有此代码,但我不想为如此通用的东西编写自己的宏、模板或函数。对于 int,有后置增量/减量运算符,但没有用于清除布尔值的后置运算符。

我现在拥有的:

bool getAndClearX()
{
    bool copy = x;
    x = false;
    return copy;
}

以下操作由于短路而无法工作:
return x || (x=false);

由于 UB(“无序修改和访问 x”),以下操作不起作用:

return x + (x=false);
return x ^ (x=false);
return x > (x=false);

这也不起作用:return std::max(x,x=false);

我不知道如何在不明确复制和不编写自己的宏、模板或函数的情况下做到这一点。使用 C++ 标准库对我来说没问题。

这个问题不是以下问题的重复:
那个是性能“可以使其更快吗”,并且接受的答案的代码行数并不少。 它还标记了 C++11,并且 std::exchange 仅在 C++14 之后可用。

9

  • “我想返回布尔变量/数据成员的当前值,并在一条语句中将其设置为 false …”为什么?微优化?


    – 


  • 2
    你有一个函数,它可以做你想做的事。这有什么问题?让编译器做它该做的事


    – 


  • 2
    请注意,您的代码不会直接转换为 CPU 指令,编译器会发挥其魔力,可能会将内容存储在寄存器中或完全消除变量,只需编写有效的代码,而不必关心语法优化


    – 

  • 我的问题是它需要 3 行代码和一个额外的变量,而它应该只需要 1 行或 2 行代码并且不需要额外的变量。这与性能无关。


    – 

  • 1
    @elechris 但您的代码可读性强、不言自明,因此易于维护。单行代码不一定是软件开发的目标。唯一的改进是使用答案中给出的更通用的函数。所以接受这一点 🙂


    – 



最佳答案
1

就是您所需要的,它为某些东西分配一个新值,同时返回其旧值。

bool getAndClearX()
{
  return std::exchange(x, false);
}

5

  • 这正是 OP 所要求的,但“在幕后”,exchange它所做的与原始版本完全相同。因此仍然“浪费”了值的getAndClearX副本 ( )。:-)old_value


    – 


  • @BoP 这与性能无关。而是与代码行数减少有关。感觉没有必要为简单的获取旧值和清除添加一个额外的变量和两行代码。这个答案很完美。我不想为这么简单的东西编写模板或函数。如果它在标准库中,它就是语言的一部分,因此我不认为这是编写额外的代码。我的应用程序是一个 GUI,我想获取指示已按下按钮的标志。在我看来,在一行中获取和清除标志更干净。我知道不是每个人都有这种偏好。


    – 

  • std::exchange()编译器可以看到你正在做什么,不会“浪费”任何东西。我早就写过一个只用于布尔值的代码,这个函数非常非常有用。顺便说一句,这个std::atomic类也有这个函数。当你用线程做事情时,这个函数特别有用。


    – 

  • 我同意这一点。我认为我们不能保证不会像问题中的代码那样进行复制。可能的实现就说明了这一点。您必须检查编译器的实现方式std::exchange才能知道是否进行了复制。


    – 

  • @DavidC.Rankin 编译器可以将显式副本编译为机器代码,而不会进行额外的复制,反之亦然。返回通常实现为寄存器(或调用堆栈)。因此,旧值被写入返回寄存器,然后在函数返回之前进行修改。不需要额外的副本。该函数甚至可能是内联的。我澄清了这个问题,这与性能无关。我将让编译器使用优化级别来生成适当的机器代码。


    –