‹ BackHN Continuity

Thread

C++26: Trivial infinite loops are no longer undefined behaviour

173 points · 290 comments · ibobev

  1. wahern · · focus · HN ↗
    > When both conditions are met, the loop body is replaced with a call to std::this_thread::yield(). This gives execution of the loop the forward-progress semantics it previously lacked.

    That's the epitome of the hidden code downside that Linus and many others dislike about C++. For constructors and destructors it's somewhat unavoidable and not so random, though Rust does better at limiting the blast radius of non-local code, at least in the drop case.

    If they didn't want to adopt the C11 rule, the C++ committee should've explored a rule that required the compiler to emit a diagnostic or error for trivial loops (whether as defined by C11 or otherwise), requiring the programmer to explicitly insert ::yield or similar. No hidden code, and less opportunity for the compiler to do surprising things.

    The C committee has been rigorously enumerating UB cases in the standard and addressing each case in turn, often by requiring a diagnostic, error, or by turning it into implemention defined behavior. But inserting code like that would be unthinkable.

    1. pbalau · · focus · HN ↗
      Is it hidden if it's explained in the standard?

      I think Linus's complain was before there was a c++ standard. An updated version of the complaint would be "this shit is doing too much".

      1. andrepd · · focus · HN ↗
        An empty loop, under some non-obvious conditions, on some compiler flags but not others, silently transforms into a system call. In a systems programming language.
        1. WalterBright · · focus · HN ↗
          I try to minimize use of destructors for the same reason.
          1. andrepd · · focus · HN ↗
            Destructors run predictably at list, and are pervasive everywhere. You know that when you exit a scope, be that a function or whatever it may, the destructors of variables in that scope are called. That is clear and consistent. The transformation mentioned above is not.
            1. WalterBright · · focus · HN ↗
              Understanding the code requires understanding the destructors of the objects you're using. Since they are invisibly inserted, they are a source difficulty in entirely understanding the code.
              1. otabdeveloper4 · · focus · HN ↗
                > Since they are invisibly inserted

                They're not, all destructors are explicit. Seems like a skill issue on your end.

                1. WalterBright · · focus · HN ↗
                  Since AFAIK I'm still the only person to write a correct C++ (C++98) compiler from preprocessor to object file, I know all about destructors.

                  Here's a fun one for your amusement:

                      foo(a, b, c);
                  
                  The parameters are pass by value. a, b and c are objects that have destructors. Have a look at the code generated for that.

                  It is nice that the compiler does the dirty work for you, but the various paths with exceptions and recovery with invisible code may not be well tested.

                2. degaart · · focus · HN ↗
                  > Seems like a skill issue on your end.

                  You're talking to walter bright, the guy who wrote the digital mars C++ compiler

                  1. otabdeveloper4 · · focus · HN ↗
                    > appeal to authority

                    Okay.

Open on Hacker News to reply ↗

Unofficial Hacker News client; not affiliated with Y Combinator.