【问题标题】:How to run code inside a loop only once without external flag?如何在没有外部标志的情况下只在循环内运行一次代码?
【发布时间】:2013-07-16 02:08:33
【问题描述】:

我想检查循环内的条件并在第一次满足时执行代码块。之后,循环可能会重复,但应该忽略该块。有这样的模式吗?当然,在循环之外声明一个标志很容易。但我对完全存在于循环中的方法感兴趣。

这个例子不是我想要的。有没有办法摆脱循环之外的定义?

bool flag = true;
for (;;) {
    if (someCondition() && flag) {
        // code that runs only once
        flag = false;
    }        
    // code that runs every time
}

【问题讨论】:

  • 为什么不将该代码移出循环?
  • 我看不出真实使用标志的问题。如果我不想这样做,我就把它移到别处。
  • 假设“移出循环”不是您想要的,您怎么知道应该只执行一次,以及“何时”执行?
  • @sharptooth 循环是一个应用程序循环,所以它一直在运行。使用异步线程对这个来说太过分了。
  • @MatsPetersson 我只想在第一次到达该块时执行给定的代码块一次。这可能是循环的第一次迭代,但由于其他条件,它也可能稍后。

标签: c++ loops design-patterns flags control-flow


【解决方案1】:

这相当 hacky,但正如你所说,它是应用程序主循环,我假设它在一个调用过的函数中,所以以下应该可以工作:

struct RunOnce {
  template <typename T>
  RunOnce(T &&f) { f(); }
};

:::

while(true)
{
  :::

  static RunOnce a([]() { your_code });

  :::

  static RunOnce b([]() { more_once_only_code });

  :::
}

【讨论】:

  • 这就是我想要的。执行完 lambda 后,我们可以在构造函数中销毁实例吗?
  • @danijar 不,它具有静态存储持续时间,因此它将在程序关闭时被破坏。问题是为什么你需要这样做。请注意,lambda 不存储在结构中,只是执行并被遗忘(即它被破坏)。 struct 实例本身可能只占用 1-4 个字节,具体取决于您的编译器,而无需对它们进行任何操作。
  • 好吧,感觉就不会那么老套了。
【解决方案2】:

对于莫比乌斯答案的不那么复杂的版本:

while(true)
{
  // some code that executes every time
  for(static bool first = true;first;first=false)
  {
    // some code that executes only once
  }
  // some more code that executes every time.
}

您也可以在 bool 上使用 ++ 来编写此代码,但这显然是 deprecated

【讨论】:

    【解决方案3】:

    一种可能更简洁的编写方式,尽管仍然使用变量,如下所示

    while(true){
       static uint64_t c;
       // some code that executes every time
       if(c++ == 0){
          // some code that executes only once
       }
       // some more code that executes every time.
     }
    

    static 允许您在循环内声明变量,恕我直言,这看起来更简洁。如果您每次执行的代码都进行了一些可测试的更改,您可以删除该变量并像这样编写它:

    while(true){
       // some code that executes every time
       if(STATE_YOUR_LOOP_CHANGES == INITIAL_STATE){
          // some code that executes only once
       }
       // some more code that executes every time.
     }
    

    【讨论】:

    • c 不会一直递增直到超过short 的范围,然后循环并在某个时候再次变为 0?
    • 明白了。上面的评论是对的,在下面的代码块内增加c 更聪明。此外,布尔标志也可以解决问题。
    • 是的,我包含了 counter 变量,因为它在一般情况下可能更有用。
    • @Mobius 我认为这不是因为每次迭代都不太可能到达唯一的一次代码块。所以计数器变量不会代表循环计数。
    • 如果您担心环绕为什么不使用 64 位 int 呢?对我的笔记本电脑进行的快速测试表明,仅数到 1.8e19(最大 64 位整数)就需要大约 1000 年。
    【解决方案4】:

    如果您知道只想运行此循环一次,为什么不使用break 作为循环中的最后一条语句。

    【讨论】:

      【解决方案5】:
      1    while(true)
      2    {
      3        if(someCondition())
      4        {
      5            // code that runs only once
      6            // ...
      7          // Should change the value so that this condition must return false from next execution.
      8        }        
      9    
      10        // code that runs every time
      11        // ...
      12    }
      

      如果您希望代码没有任何外部标志,那么您需要在条件的最后一条语句中更改条件的值。 (代码 sn-p 中的第 7 行)

      【讨论】:

      • 请阅读问题下的cmets。例如,如果玩家等级超过给定数字,他应该获得一次奖励。我不能为了两次不上奖而降低玩家等级。 while(1){ if(level &gt; 7){ once([=]{ award(); }); } }
      • 请再次阅读问题下的cmets,因为第一个问题是不使用flag如何实现,那么只有他在考虑下一个选项。
      • 标志是while循环之前的布尔变量或条件函数内的另一个标志有什么关系?
      • 这里我没有提到标志,因为我不想创建任何新的变量或标志(可重用性概念)。通过使用条件值,我们可以对其进行操作。只需验证我的代码即可。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-10-31
      相关资源
      最近更新 更多