138

Since C++ 17 one can write an if block that will get executed exactly once like this:

#include <iostream>
int main() {
    for (unsigned i = 0; i < 10; ++i) {

        if (static bool do_once = true; do_once) { // Enter only once
            std::cout << "hello one-shot" << std::endl;
            // Possibly much more code
            do_once = false;
        }

    }
}

I know I might be overthinking this, and there are other ways to solve this, but still - is it possible to write this somehow like this, so there is no need of the do_once = false at the end?

if (DO_ONCE) {
    // Do stuff
}

I'm thinking a helper function, do_once(), containing the static bool do_once, but what if I wanted to use that same function in different places? Might this be the time and place for a #define? I hope not.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
nada
  • 2,109
  • 2
  • 16
  • 23
  • 54
    Why not just `if (i == 0)`? It's clear enough. – Silvano Cerza Jun 24 '19 at 14:10
  • 27
    @SilvanoCerza Because that is not the point. This if-block might be somewhere in some function that gets executed multiple times, not in a regular loop – nada Jun 24 '19 at 14:11
  • 8
    maybe `std::call_once` is an option (it's used for threading, but still does it's job). – local-ninja Jun 24 '19 at 14:13
  • 26
    Your example may be a bad reflection of your real-world problem which you aren't showing us, but why not just lift the call-once function out of the loop? – rubenvb Jun 24 '19 at 14:15
  • `do_once--` doesn't work because `error: cannot decrement expression of type bool`. I did not know that. Never tried before. (Besides - it would get decremented multiple times, which is also not desired) – nada Jun 24 '19 at 14:34
  • @nada Not only is it not desired, it could cause underflow, leading to wraparound, and the expression running more than once (or even undefined behavior). – Davislor Jun 24 '19 at 14:38
  • 2
    @nada: Is this use case really something that comes up often enough that you want to make a macro or something to cover it? – Nicol Bolas Jun 24 '19 at 14:41
  • `bool--` was a thing in early C++ that most people agreed was a mistake and it was removed. You can see details [here](https://stackoverflow.com/questions/3450420/bool-operator-and) – meneldal Jun 25 '19 at 05:50
  • 15
    It didn't occur to me that variables initialized in an `if` conditions could be `static`. That's clever. – HolyBlackCat Jun 25 '19 at 10:08
  • 1
    @HolyBlackCat: Only true from C++17. – Bathsheba Jun 25 '19 at 10:53
  • 1
    @rubenvb Maybe it's for looping over container, and needs an idempotent action when any of the objects meets some criteria. Alternative would be a separate dedicated loop with a break. I can imagine situation where it does make sense. – luk32 Jun 26 '19 at 08:59
  • 1
    In the example code specifically, getting rid of the loop and the `if` block would be the most elegant way. Barring getting rid of the loop, the most elegant way would be to replace `do_once = false;` with `return;`, which would break the loop early and exit the function, preventing unnecessary iterations. The point is that your example code is not very good as it doesn't demonstrate the qualities that make this usage pattern needed or advisable. I strongly suggest improving it. – jpmc26 Jun 27 '19 at 03:12
  • @jpmc26 I agree, my example seems to induce confusion. Any suggestions on how to clarify the intent? – nada Jun 27 '19 at 08:53
  • @nada I think it would demonstrate your point better if your example code had the following 3 qualities: 1. [Use an iterator or range-based loop](https://stackoverflow.com/a/22269465/1394393) instead of incrementing a number. That will require some set up code before the loop. 2. Have a portion of the loop that executes unconditionally. 3. Have an additional condition based on the current item so that it wouldn't necessarily execute on the first iteration. Placeholder comments instead of actual implementations (like the one you have) for the code blocks are fine. – jpmc26 Jun 27 '19 at 20:30
  • 1
    Important to note that all of the answers that use assignment to a `static` variable are not thread-safe. (The answer that only initializes the static is safe, since the language guarantees that initialization of static is thread-safe). – M.M Jul 30 '19 at 01:47

9 Answers9

147

Use std::exchange:

if (static bool do_once = true; std::exchange(do_once, false))

You can make it shorter reversing the truth value:

if (static bool do_once; !std::exchange(do_once, true))

But if you are using this a lot, don't be fancy and create a wrapper instead:

struct Once {
    bool b = true;
    explicit operator bool() { return std::exchange(b, false); }
};

And use it like:

if (static Once once; once)

The variable is not supposed to be referenced outside the condition, so the name does not buy us much. Taking inspiration from other languages like Python which give a special meaning to the _ identifier, we may write:

if (static Once _; _)

Further improvements: take advantage of the BSS section (@Deduplicator), avoid the memory write when we have already run (@ShadowRanger), and give a branch prediction hint if you are going to test many times (e.g. like in the question):

// GCC, Clang, icc only; use [[likely]] in C++20 instead
#define likely(x) __builtin_expect(!!(x), 1)

struct Once {
    bool b = false;
    explicit operator bool()
    {
        if (likely(b))
            return false;

        b = true;
        return true;
    }
};
Acorn
  • 24,970
  • 5
  • 40
  • 69
  • 33
    I know macros get a lot of hate in C++ but this just looks so damn clean: `#define ONLY_ONCE if (static bool DO_ONCE_ = true; std::exchange(DO_ONCE_, false))` To be used as: `ONLY_ONCE { foo(); }` – Fibbs Jun 24 '19 at 17:06
  • 5
    i mean, if you write "once" three times, then use it more than three times in if statements it is worth it imo – Alan Jun 25 '19 at 08:55
  • 13
    The name `_` is used in a lot of software to mark translatable strings. Expect interesting things to happen. – Simon Richter Jun 25 '19 at 09:11
  • 1
    If you have the choice, prefer the initial value of static state to be all-bits-zero. Most executable-formats contain the length of an all-zero area. – Deduplicator Jun 25 '19 at 11:47
  • @Deduplicator +1 The first version I provide follows OP's initial code intentionally (I wanted to show how `std::exchange` fits the bill here); but, indeed, taking advantage of the bss section is better. – Acorn Jun 25 '19 at 13:09
  • Note: Using `std::exchange` writes `false` every time the check is performed, which dirties cache line & memory page backing `do_once` (I believe this happens even if you happen to be writing the same value already stored). [Bathsheba's answer](https://stackoverflow.com/a/56738565/364696) avoids this by only assigning the first time, at the expense of being slightly less pretty. – ShadowRanger Jun 25 '19 at 19:07
  • @ShadowRanger +1 Added a version with both tweaks plus a branch prediction hint that I was thinking about to show how a production version of this could look like. – Acorn Jun 25 '19 at 21:51
  • 7
    Using `_` for the variable there would be un-Pythonic. You don't use `_` for variables that will be referenced later, only to store values where you *have* to provide a variable but you don't need the value. It's typically used for unpacking when you only need some of the values. (There are other use cases, but they're quite different from the throwaway value case.) – jpmc26 Jun 27 '19 at 03:05
  • While an excellent display of technical coding, this is almost certainly terrible software engineering practice. If I was reviewing a pull request for this solution, I would tell the offender to go back and use the OP's solution and stop building extraneous classes of marginal utility. – kingledion Jun 27 '19 at 14:33
  • @jpmc26 The Python idiom is about ignoring values. Here `_` is used as a variable that is not intended to be referenced anywhere except the condition. This is not about being Pythonic or not, but rather about importing `_` for a similar purpose. In C++ we cannot re-define/re-bind variables like in Python anyway, so it is not that useful. However, we do have cases in C++ where such a possibility would be neat. – Acorn Jun 27 '19 at 17:21
  • @Acorn Its reference in the condition is a reference. The variable is intended to persist throughout the loop. Putting aside that "ignore" is the wrong way to think about it ("discard" is a more appropriate term), that is not ignoring it. Whatever you intentions are, the underscore idiom in Python is not what your answer implies. I'm going to clarify the answer you link. – jpmc26 Jun 27 '19 at 17:52
  • @jpmc26 I understand what you mean, but it was not intended to be exactly that idiom. Instead, about using the `_` identifier for a special purpose (in this case, give a name to a variable that should not be used outside the condition). It is indeed not about discarding/ignoring the value here, but it is about ignoring the variable name, that was my point. :) Since I agree that it can be misleading, I have clarified it in the answer, take a look! – Acorn Jun 29 '19 at 12:44
91

Maybe not the most elegant solution and you don't see any actual if, but the standard library actually covers this case:, see std::call_once.

#include <mutex>

std::once_flag flag;

for (int i = 0; i < 10; ++i)
    std::call_once(flag, [](){ std::puts("once\n"); });

The advantage here is that this is thread safe.

lubgr
  • 37,368
  • 3
  • 66
  • 117
  • 3
    I wasn't aware of std::call_once in that context. But with this solution you need to declare a std::once_flag for every place you use that std::call_once, don't you? – nada Jun 24 '19 at 14:18
  • Yes, every `once_flag` instance guards the execution of the callable(s) passed to `call_once`. – lubgr Jun 24 '19 at 14:19
  • 11
    This works, but wasn't meant for a simple if solution, the idea is for multithreaded applications. It's overkill for something that simple because it uses internal synchronization - all for something that would be solved by a plain if. He was not asking for a thread safe solution. – Michael Chourdakis Jun 24 '19 at 14:20
  • 10
    @MichaelChourdakis I agree with you, it's an overkill. However, it's worth knowing about, and especially knowing about the possibility to express what you're doing ("execute this code once") instead of hiding something behind a less readable if-trickery. – lubgr Jun 24 '19 at 14:23
  • @MichaelChourdakis Indeed, seeing `std::call_once` would make me think this is trying to prevent several threads running the code. – Acorn Jun 24 '19 at 14:29
  • 19
    Uh, seeing `call_once` to me means you want to call something once. Crazy, I know. – Barry Jun 24 '19 at 14:29
  • 1
    @MichaelChourdakis to me it is not overkill, but rather idiomatic way of doing something once. I do not see how it is overkill. – SergeyA Jun 24 '19 at 14:49
  • 3
    @SergeyA because it uses internal synchronization - all for something that would be solved by a plain if. It's a rather idiomatic way of doing something other than what was asked for. – Lightness Races in Orbit Jun 24 '19 at 14:54
  • 1
    seems to be the better option than `std::exchange` but should be noted as synchronised across threads and might add a performance penalty – Tarick Welling Jun 24 '19 at 14:58
  • 2
    @LightnessRacesinOrbit I looked at call_once implementation in gcc, and as long as you have support for TLS, there is no explicit synchronization. I wasn't able to quickly find LLVM's implementation for it. – SergeyA Jun 24 '19 at 15:02
  • 2
    @SergeyA Can't speak for how it's implemented, but the concurrency is required. Read more about it [here](https://en.cppreference.com/w/cpp/thread/call_once). Do note though that the `static` var example's init (but not the check or set) is thread-safe too. (In fact that linked article literally says _"Initialization of function-local statics is guaranteed to occur only once even when called from multiple threads, and may be more efficient than the equivalent code using std::call_once."_) – Lightness Races in Orbit Jun 24 '19 at 15:12
  • 2
    I know there's some overhead because of the synchronization, but this does seem like by far the most elegant way. I don't see the problem with having to declare a single variable before the `if` statement. It's far more clear and readable than `if (static bool do_once = true; std::exchange(do_once, false))` and similar solutions, and the intent is much more clear than creating a wrapper struct. I don't know much C++ but all the other solutions involving static variables seem pretty hacky. – Addison Jun 25 '19 at 19:10
  • 1
    @LightnessRacesinOrbit: The fast-path in a good implementation (the already-done case) should just compile to a normal load from static storage (same as for a normal `static` variable, or atomic with `memory_order_relaxed`) and a not-taken fall-through compare+branch. Same as gcc/clang make for a static local variable with a non-constant initializer, with a guard variable. If a `call_once()` implementation doesn't compile that way, it's a missed optimization in the library and/or compiler. The path that does run the if body is barely relevant for perf in most use-cases. – Peter Cordes Jun 27 '19 at 05:52
  • @PeterCordes Indeed, it _could_ be as fast. Missed optimisations do exist though! I don't really see the purpose in chancing it when a simpler solution won't be slower. – Lightness Races in Orbit Jun 27 '19 at 09:26
  • 1
    @Addison Using a `static` variable in other solutions is optional, you could also add a non-static one like here with `std::once_flag`. I don't see anything hacky about using utility classes to describe a pattern, it is quite common in C++. – Acorn Jun 27 '19 at 17:30
52

C++ does have a builtin control flow primitive that consists of "(before-block; condition; after-block)" already:

for (static bool b = true; b; b = false)

Or hackier, but shorter:

for (static bool b; !b; b = !b)

However, I think any of the techniques presented here should be used with care, as they are not (yet?) very common.

Sebastian Mach
  • 38,570
  • 8
  • 95
  • 130
  • 1
    I like the first option (though - like many variants here - it is not thread safe, so be careful). The second option gives me chills (harder to read and may be executed any number of times with only two threads... `b == false`: `Thread 1` evaluates `!b` and enters for loop, `Thread 2` evaluates `!b` and enters for loop, `Thread 1` does its stuff and leaves the for loop, setting `b == false` to `!b` i.e. `b = true`... `Thread 2` does its stuff and leaves the for loop, setting `b == true` to `!b` i.e. `b = false`, allowing the whole process to be repeated indefinitely) – CharonX Jun 27 '19 at 11:25
  • 4
    I find it ironic that one of the most elegant solutions to a problem, where some code is supposed to be executed only once, is a *loop*. +1 – nada Jun 27 '19 at 13:56
  • 2
    I would avoid `b=!b`, that's looks nice, but you actually want the value to be false, so `b=false` shall be preferred. – yo' Jun 27 '19 at 19:51
  • 2
    Be aware that the protected block will run again if it exits non-locally. That might even be desirable, but it’s different from all the other approaches. – Davis Herring Jul 11 '19 at 22:50
29

In C++17 you can write

if (static int i; i == 0 && (i = 1)){

in order to avoid playing around with i in the loop body. i starts with 0 (guaranteed by the standard), and the expression after the ; sets i to 1 the first time it is evaluated.

Note that in C++11 you could achieve the same with a lambda function

if ([]{static int i; return i == 0 && (i = 1);}()){

which also carries a slight advantage in that i is not leaked into the loop body.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 4
    I'm sad to say - if that'd be put in a #define called CALL_ONCE or so it'd be more readable – nada Jun 24 '19 at 14:21
  • 10
    While `static int i;` might (I'm truly not sure) be one of those cases where `i` is guaranteed to be initialized to `0`, it's much clearer to use `static int i = 0;` here. – Kyle Willmon Jun 24 '19 at 14:22
  • @nada: Yes it's not simple to read, but this was never going to be a simple task. But the fact that it *can* be done is a touchstone of the power of C++! – Bathsheba Jun 24 '19 at 14:22
  • 2
    @KyleWillmon: No it's guaranteed by the standard. – Bathsheba Jun 24 '19 at 14:22
  • 8
    Regardless I agree an initialiser is a good idea for comprehension – Lightness Races in Orbit Jun 24 '19 at 14:25
  • 1
    @LightnessRacesinOrbit: If you're aiming for comprehension then use `std::call_once`. – Bathsheba Jun 24 '19 at 14:28
  • 1
    There's a gaping chasm between writing `= 0` for clarity, and introducing a wholly synchronised solution. – Lightness Races in Orbit Jun 24 '19 at 14:29
  • 1
    @LightnessRacesinOrbit: But why? *Everyone* knows that `static` storage `int`s are initialised to 0. – Bathsheba Jun 24 '19 at 14:30
  • 5
    @Bathsheba Kyle didn't, so your assertion has already been proven false. What does it cost you to add two characters for the sake of clear code? Come on, you're a "chief software architect"; you should know this :) – Lightness Races in Orbit Jun 24 '19 at 14:33
  • 2
    @LightnessRacesinOrbit: But I don't find it clearer. The contrary actually. Extra bits in code imply something funky is happening. Not too far removed from `if (n == true)` But we've long established I'm not normal. – Bathsheba Jun 24 '19 at 14:35
  • 6
    If you think spelling out the initial value for a variable is the contrary of clear, or suggests that "something funky is happening", I don't think you can be helped ;) – Lightness Races in Orbit Jun 24 '19 at 14:36
  • 3
    I'd prefer this with a `bool`: `if(static bool hasRun = false; !hasRun && (hasRun = true))`. And, yes, I also think a `#define` is in order: `#define RUN_ONCE if(static bool hasRun = false; !hasRun && (hasRun = true))`, allowing us to say `RUN_ONCE { /* stuff */ }` – cmaster - reinstate monica Jun 25 '19 at 09:48
  • 1
    @cmaster: Hum, perhaps 6 of one and 1/2 dozen of the other. Personally I don't like to call it `hasRun` as it's a misnomer: it's `true` in the loop body. I also dislike the superfluous initialisation, but enough said on that already. – Bathsheba Jun 25 '19 at 09:50
  • As far as readability it's not super clear either way. But `int` wastes 3 extra bytes on most implementations. Byte loads on some non-x86 microarchitectures may have 1 extra cycle of latency vs. `int` loads, but in this case that latency will normally be hidden by branch speculation on any out-of-order CPU. – Peter Cordes Jun 27 '19 at 05:57
  • @KyleWillmon: All variables with static duration are initialized (to zero if nothing else), because there’s no “previous value” to leave in their bytes (to save a cycle). If anyone doesn’t already know that, making them think about it is something of a service. – Davis Herring Jul 11 '19 at 22:54
15
static bool once = [] {
  std::cout << "Hello one-shot\n";
  return false;
}();

This solution is thread safe (unlike many of the other suggestions).

Waxrat
  • 510
  • 2
  • 11
9

You could wrap the one-time action in the constructor of a static object that you instantiate in place of the conditional.

Example:

#include <iostream>
#include <functional>

struct do_once {
    do_once(std::function<void(void)> fun) {
        fun();
    }
};

int main()
{
    for (int i = 0; i < 3; ++i) {
        static do_once action([](){ std::cout << "once\n"; });
        std::cout << "Hello World\n";
    }
}

Or you may indeed stick with a macro, that may look something like this:

#include <iostream>

#define DO_ONCE(exp) \
do { \
  static bool used_before = false; \
  if (used_before) break; \
  used_before = true; \
  { exp; } \
} while(0)  

int main()
{
    for (int i = 0; i < 3; ++i) {
        DO_ONCE(std::cout << "once\n");
        std::cout << "Hello World\n";
    }
}
moooeeeep
  • 31,622
  • 22
  • 98
  • 187
8

Like @damon said, you can avoid using std::exchange by using a decrementing integer, but you have to remember that negative values resolve to true. The way to use this would be:

if (static int n_times = 3; n_times && n_times--)
{
    std::cout << "Hello world x3" << std::endl;
} 

Translating this to @Acorn's fancy wrapper would look like this:

struct n_times {
    int n;
    n_times(int number) {
        n = number;
    };
    explicit operator bool() {
        return n && n--;
    };
};

...

if(static n_times _(2); _)
{
    std::cout << "Hello world twice" << std::endl;
}
Oreganop
  • 81
  • 1
7

While using std::exchange as suggested by @Acorn is probably the most idiomatic way, an exchange operation is not necessarily cheap. Although of course static initialization is guaranteed to be thread-safe (unless you tell your compiler not to do it), so any considerations about performance are somewhat futile anyway in presence of the static keyword.

If you are concerned about micro-optimization (as people using C++ often are), you could as well scratch bool and use int instead, which will allow you to use post-decrement (or rather, increment, as unlike bool decrementing an int will not saturate to zero...):

if(static int do_once = 0; !do_once++)

It used to be that bool had increment/decrement operators, but they were deprecated long ago (C++11? not sure?) and are to be removed altogether in C++17. Nevertheless you can decrement an int just fine, and it will of course work as a Boolean condition.

Bonus: You can implement do_twice or do_thrice similarly...

Damon
  • 67,688
  • 20
  • 135
  • 185
  • I tested this and it fires multiple times except for the first time. – nada Jun 26 '19 at 21:40
  • @nada: Silly me, you're right... corrected it. It used to work with `bool` and decrement once upon a time. But increment works fine with `int`. See online demo: http://coliru.stacked-crooked.com/a/ee83f677a9c0c85a – Damon Jun 27 '19 at 13:35
  • 1
    This still has the problem that it might get executed so many times that `do_once` wraps around and will eventually hit 0 again (and again and again...). – nada Jun 27 '19 at 13:51
  • To be more precise: This would now get executed every INT_MAX times. – nada Jun 27 '19 at 14:14
  • Well yes, but apart from the loop counter _also_ wrapping around in that case, it's hardly a problem. Few people run 2 billion (or 4 billion if unsigned) iterations of anything at all. If they do, they could still use a 64-bit integer. Using the fastest available computer, you'll die before it wraps around, so you cannot be sued for it. – Damon Jun 27 '19 at 14:52
  • That loop is just there to emphasize the `if` gets executed multiple times. It has already been established, that my example as is distracts from the underlying question. Sorry for that. – nada Jun 27 '19 at 17:43
4

Based on @Bathsheba's great answer for this - just made it even simpler.

In C++ 17, you can simply do:

if (static int i; !i++) {
  cout << "Execute once";
}

(In previous versions, just declare int i outside the block. Also works in C :) ).

In simple words: you declare i, which takes default value of zero (0). Zero is falsey, therefore we use exclamation mark (!) operator to negate it. We then take into account the increment property of the <ID>++ operator, which first gets processed (assigned, etc) and then incremented.

Therefore, in this block, i will be initialized and have the value 0 only once, when block gets executed, and then the value will increase. We simply use the ! operator to negate it.

Nick Louloudakis
  • 5,856
  • 4
  • 41
  • 54