Live data from Hacker News

C++26 is done: ISO C++ standards meeting Trip Report

herbsutter.com

271–280 of 437 posts

Re: C++26 is done: ISO C++ standards meeting Trip Report

#271

Earlier quoted context omitted.

D initializes all variables. If you don't provide an initializer, the compiler inserts the default initializer for it. But if you really, really want to leave it uninitialized, write: int x = void; where you're not writing that by accident.

That is a way better syntax. I wonder why C++ didn't adopt it.

Because you can't adopt that syntax after the fact. there is 30 years of C++ in the real world, initializing everything by default unless you opt-in will break some performance critical code that should not initialize everything (until it is updated manually - it has to be manual because tools are not smart enough to know where something was intentionally not initialized 100% of the time)

Thus the current erroneous. It means this isn't a bug (compilers used to optimized out code paths where an uninitialized value is read and this did cause real world bugs when it doesn't matter what value is read). It also means the compiler is free to put whatever value they want there - one of the goals was the various sanitizers that check for using uninitialized values need to still work - the vast majority of the time when an uninitialized value is read that is a bug in the code.

There are a lot of situations where a compiler cannot tell if a variable would be used uninitialized, so we can't rely on compiler warnings (it sometimes needs solving the halting problem).

Re: C++26 is done: ISO C++ standards meeting Trip Report

#272

If C++29 was exclusively about quality-of-life improvements, improving what exists, I'd bet the community wouldn't mind too much.

That depends on what else comes. There are a lot of ideas, some of which will get the community excited.

Re: C++26 is done: ISO C++ standards meeting Trip Report

#273

The "erroneous behavior" redefinition for reads of uninitialized variables is really interesting: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p27... It does have a runtime cost. There's an attribute to force undefined behavior on read again and avoid the cost: int x [[indeterminate]]; std::cin >> x;

D initializes all variables. If you don't provide an initializer, the compiler inserts the default initializer for it. But if you really, really want to leave it uninitialized, write: int x = void; where you're not writing that by accident.

> If you don't provide an initializer, the compiler inserts the default initializer for it.

This requires that there is a default. Several modern languages (such as Go) insist on this, it means now your types don't even model reality in this very fundamental way. Who is a person's default spouse? Even where you can imagine a default it's sometimes undesirable to have one, for example we already live in a society where somebody decided default gender is male - and it might look too much like real data, default birthday being 1 January also matches hundreds of thousands of Americans...

The most likely place you go after "Everything has a default" is the billion dollar mistake because you're inclined to just incorporate "or it's default invalid" into the type definition to get your default, and when you do that everywhere needs to have "check it's valid" code added, even if we already just checked that a moment ago.

Re: C++26 is done: ISO C++ standards meeting Trip Report

#274
post #131
post #40

Earlier quoted context omitted.

You don't on new projects. CMake + ninja has support for modules on gcc, clang, and MSVC. This should be your default stack on any small-to-medium sized C++ project. Bazel, the default pick for very large codebases, also has support for C++20 modules.

I have yet to see modules in the wild. What I have seen extensively are header-only projects.

Modules need a lot of tooling. The tool vendors have been working hard on this for years. They have only just now said this is ready for early adopters. Most people are waiting for the early adopters to write the books on what best practices are - this needs a few more years of experience.

Re: C++26 is done: ISO C++ standards meeting Trip Report

#275
post #247

The "erroneous behavior" redefinition for reads of uninitialized variables is really interesting: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p27... It does have a runtime cost. There's an attribute to force undefined behavior on read again and avoid the cost: int x [[indeterminate]]; std::cin >> x;

On a quick read of the paper, I see two surprising things: 1. If there’s no initializer and various conditions are met, then “the bytes have erroneous values, where each value is determined by the implementation independently of the state of the program. What does “independently” mean? Are we talking about all zeros? Is the implementation not permitted to use whatever arbitrary value was in memory? Why not? 2. What’s…

> What does “independently” mean?

It can pick whatever value it wants and doesn't have to care what the program is doing.

Also the value has to stay the same until it's 'replaced'.

> Are we talking about all zeros?

It might be, but probably won't be. What makes you bring up all zeroes?

> Is the implementation not permitted to use whatever arbitrary value was in memory? Why not?

(Edit: probably wrong, also affects other things I said) It can. What suggests it wouldn't be able to?

> 2. What’s up with [[indeterminate]]? I would expect “indeterminate” to mean that the variable has a value that happens to be arbitrary (and may contain sensitive data, etc), not that it turns back into actual UB.

"has a value that happens to be arbitary" would be the default without [[indeterminate]]. Well, it can also error out if the compiler wants to do that.

Re: C++26 is done: ISO C++ standards meeting Trip Report

#276

If you ask me (and why wouldn't you? :-)...) I really wish the C++ WG would do several things: 1. Standardize a `restrict` keyword and semantics for it (tricky for struct/class fields, but should be done). 2. Uniform Function Call Syntax! That is, make the syntax `obj.f(arg)` mean simply `f(obj, arg)` . That would make my life much easier, both as a user of classes and as their author. In my library authoring work pa…

2 sounds good, but it will break a lot of existing code what suddenly does something different. At least so far every version of the rules someone has come up with has had a real world example of code that would be seriously broken if it was in place.

Re: C++26 is done: ISO C++ standards meeting Trip Report

#277
post #189

Earlier quoted context omitted.

A pointer doesn't necessarily point to memory.

A nitpick to your nitpick: they said "memory location". And yes, a pointer always points to a memory location. Notwithstanding that each particular region of memory locations could be mapped either to real physical memory or any other assortment of hardware.

You can point to a register which is certainly not memory.

Re: C++26 is done: ISO C++ standards meeting Trip Report

#278
post #6

Finally, reflection has arrived, five years after I last touched a line in c++. I wonder how long would it take the committee, if ever, to introduce destructing move.

What do you mean by a destructing move? Are you trying to avoid use of a moved object after you've moved it? eg. B = std::move(A); // You are worried about touching A when it's in this indeterminate state?

destructive moves are required to make moves zero cost.

Currently move semantics in C++ requires that A is left in a 'moved from, but valid state' which means that:

1. The compiler must still generate code that calls the destructor.

2. Every destructor need have to have some flag and a test in it like: if(moved_from) // do nothing else { free_resources(); }

(Granted, for some simple types the compiler might inline and removed redundant checks so it ends up with no extra code, but that is not guaranteed)

With destructive moves the compiler can just forget about the object completely, no need to call it, destructurs can be written as normal and only care about the invariants established in the constructor.

Re: C++26 is done: ISO C++ standards meeting Trip Report

#279

Earlier quoted context omitted.

That is a way better syntax. I wonder why C++ didn't adopt it.

Because you can't adopt that syntax after the fact. there is 30 years of C++ in the real world, initializing everything by default unless you opt-in will break some performance critical code that should not initialize everything (until it is updated manually - it has to be manual because tools are not smart enough to know where something was intentionally not initialized 100% of the time) Thus the current erroneous.…

> There are a lot of situations where a compiler cannot tell if a variable would be used uninitialized, so we can't rely on compiler warnings (it sometimes needs solving the halting problem).

It's an explicit choice in C++ to always accept correct programs (the alternative being to always reject incorrect programs†). The committee does not have to stick by this bad decision in each C++ version, of course they aren't likely to stop making the same bad choice, but it is possible to do so.

If you're allowed to take the other side, you can of course (Rust and several other languages do this) reject programs where the compiler isn't satisfied that you definitely always initialize the variable before it's value is needed. Most obviously (but it's pretty annoying, so Rust does not do this) you could insist on the initialization as part of the variable definition in the actual syntax.

† You can't have both, by Rice's Theorem, Henry Rice got his PhD for figuring out how to prove this, last century, long before C++ was conceived. So you must pick, one or the other.

Re: C++26 is done: ISO C++ standards meeting Trip Report

#280
post #247

The "erroneous behavior" redefinition for reads of uninitialized variables is really interesting: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p27... It does have a runtime cost. There's an attribute to force undefined behavior on read again and avoid the cost: int x [[indeterminate]]; std::cin >> x;

On a quick read of the paper, I see two surprising things: 1. If there’s no initializer and various conditions are met, then “the bytes have erroneous values, where each value is determined by the implementation independently of the state of the program. What does “independently” mean? Are we talking about all zeros? Is the implementation not permitted to use whatever arbitrary value was in memory? Why not? 2. What’s…

> What does “independently” mean?

It means what it says on the tin. Whatever value ends up being used must not depend on the state of the program.

> Are we talking about all zeros?

All zeros is an option, but the intent is to allow the implementation to pick other values as it sees fit:

> Note that we do not want to mandate that the specific value actually be zero (like P2723R1 does), since we consider it valuable to allow implementations to use different “poison” values in different build modes. Different choices are conceivable here. A fixed value is more predictable, but also prevents useful debugging hints, and poses a greater risk of being deliberately relied upon by programmers.

> Is the implementation not permitted to use whatever arbitrary value was in memory?

No, because the value in such a case can depend on the state of the program.

> Why not?

Doing so would defeat the purpose of the change, which is to turn nasal-demons-on-mistake into something with less dire consequences:

> In other words, it is still an "wrong" to read an uninitialized value, but if you do read it and the implementation does not otherwise stop you, you get some specific value. In general, implementations must exhibit the defined behaviour, at least up until a diagnostic is issued (if ever). There is no risk of running into the consequences associated with undefined behaviour (e.g. executing instructions not reflected in the source code, time-travel optimisations) when executing erroneous behaviour.

> What’s up with [[indeterminate]]?

The idea is to provide a way to opt into the old full-UB behavior if you can't afford the cost of the new behavior.

> I would expect “indeterminate” to mean that the variable has a value that happens to be arbitrary (and may contain sensitive data, etc), not that it turns back into actual UB.

I believe the spelling matches how the term was used in previous standards. For example, from the C++23 standard [0] (italics in original):

> When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced.

[0]: https://open-std.org/JTC1/SC22/WG21/docs/papers/2023/n4950.p...

Post reply on HN