waynecochran 1 day ago

This idea that everything must be initialized (i.e. no undefined or non-deterministic behavior) should never be forced upon a language like C++ which rightly assumes the programmer should have the final say. I don't want training wheels put on C++ -- I want C++ do exactly and only what the programmer specifies and no more. If the programmer wants to have uninitialized memory -- that is her business.

13
Maxatar 1 day ago

It's so ironic hearing a comment like this. If what you really want is for C++ to do only what you strictly specified, then you'd always release your software with all optimizations disabled.

But I'm going to go out on a limb here and guess you don't do that. You actually do allow the C++ compiler to make assumptions that are not explicitly in your code, like reorder instructions, hoist invariants, eliminate redundant loads and stores, vectorize loops, inline functions, etc...

All of these things I listed are based on the compiler not doing strictly what you specified but rather reinterpreting the source code in service of speed... but when it comes to the compiler reinterpreting the source code in service of safety.... oh no... that's not allowed, those are training wheels that real programmers don't want...

Here's the deal... if you want uninitialized variables, then explicitly have a way to declare a variable to be uninitialized, like:

    int x = void;
This way for the very very rare cases where it makes a performance difference, you can explicitly specify that you want this behavior... and for the overwhelming majority of cases where it makes no performance impact, we get the safe and well specified behavior.

sixthDot 1 day ago

> int x = void;

this is what the D programming language does. Every var declaration has a well know value, unless it is initialized with void. This is nice, optimizing compilers are able to drop useless assignments anyway.

trealira 1 day ago

Nah, they'd never add new syntax like that, given it's inconsistent with the rest of C++.

If they added an explicit uninitialized value representation to the language, I bet it would look something like this:

  int x {std::uninitialized<int>::value};

Maxatar 1 day ago

You're not far off. In C++26 the syntax will be:

   int x [[indeterminate]];
I'm not kidding here;

gpderetta 1 day ago

C++ hasn't done it this way for nullptr or nullopt, why would it do it for an explicit uninitialized?

trealira 1 day ago

I guess nullptr was put in there because because because "#define NULL 0" had some bad consequences for C++ and they needed a replacement.

std::nullopt doesn't seem so different to what I was talking about; I guess it's just less verbose. When I wrote that, I was thinking of things like "std::is_same<T1, T2>::value" being there.

tlb 1 day ago

That's about the right level of ceremony to request an uninitialized variable.

frollogaston 1 day ago

How about int x = 0 if you want 0. Just `int x;` doesn't make it clear that you want 0.

kstrauser 1 day ago

Safe defaults matter. If you're using x to index into a array, and it's randomly initialized as +-2,000,000,000 because that's what happened to be in that RAM location when the program launched, and you use it before explicitly setting it, you're gonna have a bad time.

And if you used it with a default value of 0, you're going to end up operating on the 0th item in the array. That's probably a bug and it may even be a crasher if the array has length 0 and you end up corrupting something important, but the odds of it being disastrous are much lower.

waynecochran 1 day ago

The whole advantage of UB is that this places less restraints on what the optimizer can do. If I say something does not need to be initialized I am giving the optimizer the freedom to do more!

TheBicPen 1 day ago

So what's the issue with introducing explicit syntax to do exactly that if you want to? A safe default does not preclude you from opting out of safety with a bit of syntax or perhaps a compiler flag.

monkeyelite 1 day ago

The issue is that the language was already designed with the old behavior.

monkeyelite 1 day ago

> It's so ironic hearing a comment like this. If what you really want is for C++ to do only what you strictly specified, then you'd always release your software with all optimizations disabled

The whole idea of optimizations is producing code that’s equivalent to the naiive version you wrote. There is no inconsistency here.

RUnconcerned 1 day ago

Optimizations are not "exactly and only what the programmer specifies and no more". They actually fall into the "more" category, believe it or not.

monkeyelite 1 day ago

Show me some O2 optimizations that will act contrary to code I wrote - meaning they violate the “as if” rule.

Maxatar 1 day ago

Two points... the first is you want an optimization that violates the "as if" rule, sure... copy constructors are allowed to violate the "as if" rule, so here you go:

    https://godbolt.org/z/jzWWTW85j
Compile that without optimizations and you get one set of output, compile it with optimizations and you get another. There are actually an entire suite of exceptions to the "as-if" rule.

The second point is that the whole reason for having an "as if" rule in the first place is to give permission for the compiler to discard the literal interpretation of the source code and instead only consider semantics that are defined to be observable, which the language standard defines not you the developer.

There would be no need for an "as if" rule if the compiler strictly did exactly what it was told. Its very existence should be a clue that the compiler is allowed to reinterpret the source code in ways that do not reflect its literal interpretation.

William_BB 9 hours ago

The standard says that "Copy elision is <...> one of the two allowed forms of optimization, alongside allocation elision and extension,(since C++14) that can change observable side-effects"

I agree you have a valid point though. I'd be interested to know the committee's reasoning.

monkeyelite 14 hours ago

> if the compiler strictly did exactly what it was told.

What does this mean since I am not writing assembly and there is no specified correspondence between assembly and C++.

RUnconcerned 1 day ago

I dunno about what you wrote, but here is one that clearly violates what OP said!

https://godbolt.org/z/Y4Yjb7z9c

clang notices that in the second loop I'm multiplying by 0, and thus the result is just 0, so it just returns that. Critically, this is not "exactly and only what the programmer specifies", since I very much told it to do all those additions and multiplications and it decided to optimize them away.

monkeyelite 14 hours ago

What? But the result is the same!

yxhuvud 1 day ago

The discussion about what should be the default behavior and of what should be the opt-in behavior is very different from what should be possible. It is definitely clear that in c++, it must be possible to not initialize variables.

Would it really be that unreasonable to have initialisation be opt-out instead of opt-in? You'd still have just as much control, but it would be harder to shoot yourself in the foot by mistake. Instead it would be slightly more easy to get programs that can be optimised.

frollogaston 1 day ago

C++ is supposed to be an extension of C, so I wouldn't expect things to be initialized by default, even though personally I'm using C++ for things where it'd be nice.

I'm more annoyed that C++ has some way to default-zero-init but it's so confusing that you can accidentally do it wrong. There should be only one very clear way to do this, like you have to put "= 0" if you want an int member to init to 0. If you're still concerned about safety, enable warnings for uninitialized members.

dwattttt 1 day ago

C++ is supposed to be an extension of <thing with bad default>, so I wouldn't expect <a good default>.

Things can change & grow, that's why we make new standards in the first place.

frollogaston 1 day ago

It'd be confusing for C++ to differ from C in how primitives work. If they want to evolve C too then sure.

frollogaston 1 day ago

also there are compiler warnings for uninitialized variables

gpderetta 1 day ago

my_type my_var = {}; almost always does the right thing.

The almost is unfortunate.

loeg 1 day ago

As someone who has to work in C++ day in and day out: please, give me the fucking training wheels. I don't want UB if I declare an object `A a;` instead of `A a{};`. At least make it a compiler error I can enable!

ryandrake 1 day ago

Ideally, there would be a keyword for it. So ‘A a;’ would not compile. You’d need to do ‘A a{};’ or something like ‘noinit A a;’ to tell the compiler you’re sure you know what you are doing!

bregma 1 day ago

Can you identify a compiler released in the last, say, 20 years that does not give a warning (or error, if the compiler is instructed to turn warnings into errors) for uninitialized variables when warnings are enabled?

int_19h 16 hours ago

Most of them. They have to, because declaring an uninitialized variable that is later initialized by passing a reference or pointer to it to some initialization function is a rather common pattern in low-level C++.

In a sane language that would be distinguishable by having the direction explicit (i.e. things like in/out/ref in C#), and then compiler could complain for in/ref but not for out. But this is C++, so...

loeg 22 hours ago

Does Clang 20 (March 2025) meet your criteria?

https://godbolt.org/z/W9Tzhfn4s

waynecochran 1 day ago

Not me. I want to give the optimizer the freedom to do its thing. If I say something does not need to be initialized, then the optimizer has one less constraint to worry about.

wiseowise 1 day ago

We’ve already understood you don’t want sane language design, you don’t need to repeat it ten times.

90s_dev 1 day ago

That's the inherent tension, though, isn't it?

A programmer wants the compiler to accept code that looks like a stupid mistake when he knows it's not.

But he also wants to have the compiler make sure he isn't making stupid mistakes by accident.

How can it do both? They're at odds.

wiseowise 1 day ago

> How can it do both? They're at odds.

By doing what’s right.

https://en.wikipedia.org/wiki/Principle_of_least_astonishmen...

90s_dev 1 day ago

Appealing to intuition doesn't work. The way DHH thinks is the complete opposite of people like me who love TypeScript but could never make heads or tails of Rails.

kstrauser 1 day ago

By that logic, you'd have to dislike the situations where C++ does already initialize variables to defined values, like `int i;`, because they're removing your control and forcing training wheels upon you.

So, do you?

jcelerier 1 day ago

    int i;
does not initialize the value.

kstrauser 1 day ago

It's a gotcha to be sure. Sometimes it does, sometimes it doesn't. From a reference[0]:

  #include <string>
  
  struct T1 { int mem; };
  
  struct T2
  {
      int mem;
      T2() {} // “mem” is not in the initializer list
  };
  
  int n; // static non-class, a two-phase initialization is done:
  // 1) zero-initialization initializes n to zero
  // 2) default-initialization does nothing, leaving n being zero
  
  int main()
  {
      [[maybe_unused]]
      int n;            // non-class, the value is indeterminate
      std::string s;    // class, calls default constructor, the value is ""
      std::string a[2]; // array, default-initializes the elements, the value is {"", ""}
      //  int& r;           // Error: a reference
      //  const int n;      // Error: a const non-class
      //  const T1 t1;      // Error: const class with implicit default constructor
      [[maybe_unused]]
      T1 t1;            // class, calls implicit default constructor
      const T2 t2;      // const class, calls the user-provided default constructor
      // t2.mem is default-initialized
  }
That `int n;` on the 11th line is initialized to 0 per standard. `int n;` on line 18, inside a function, is not. And `struct T1 { int mem; };` on line 3 will have `mem` initialized to 0 if `T1` is instantiated like `T1 t1{};`, but not if it's instantiated like `T1 t1;`. There's no way to tell from looking at `struct T1{...}` how the members will be initialized without knowing how they'll be called.

C++ is fun!

[0]https://en.cppreference.com/w/cpp/language/default_initializ...

90s_dev 1 day ago

Stroustrup once said

> "There's a great language somewhere deep inside of C++"

or something to that effect.

int_19h 16 hours ago

Yes, it's called Simula-67.

(the original pre-ISO C++ is basically C with Simula bolted onto it.)

portaltonowhere 1 day ago

Unless `i` is global…

waynecochran 1 day ago

Most cases, e.g. local var declaration. `int i` does not initialize i.

charlotte-fyi 1 day ago

The entire problem is that what the programmer wants to do and what the program actually does isn't always clear to the programmer.

GrantMoyer 1 day ago

The problem is that the initialization semantics are so complex in C++ that almost no programmer is actually empowered to exercise their final say, and no programmer without significant effort.

And that's not just said out of unfamiliarity. I'm a professional C++ developer, and I often find I'm more familiar with C++'s more arcane semantics than many of my professional C++ developer co-workers.

marsten 1 day ago

Unfortunately C++ ended up with a set of defaults (i.e., the most ergonomic ways of doing things) that are almost always the least safe. During most of C++'s development, performance was king and so safety became opt-in.

Many of these can't be blamed on C holdover. For example Vector.at(i) versus Vector[i] – most people default to the latter and don't think twice about the safety implications. The irony is that most of the time when people use std::vector, performance is irrelevant and they'd be much better off with a safe default.

Alas, we made our bed and now we have to lie in it.

int_19h 16 hours ago

vector::at() is an interesting example. Most of the time, you don't use it because you don't index vectors in the first place - you use iterators, and there's no equivalent of at() for them that is guaranteed to throw when out of bounds.

anon-3988 1 day ago

If they want the program to do exactly what is told they won't get to have optimization.

dminik 1 day ago

It doesn't really seem worth it. https://web.ist.utl.pt/nuno.lopes/pubs/ub-pldi25.pdf

> The results show that, in the cases we evaluated, the performance gains from exploiting UB are minimal. Furthermore, in the cases where performance regresses, it can often be recovered by either small to moderate changes to the compiler or by using link-time optimizations.

waynecochran 1 day ago

That's the whole point of UB -- it leaves open more possibilities for optimization. If everything is nailed down, then the options are more restricted.

titzer 1 day ago

> I want C++ do exactly and only what the programmer specifies and no more.

Most programmers aren't that good and you're mostly running other people's code. Bad defaults that lead to exploitable security bugs is...bad defaults. If you want something to be uninitialized because you know it then you should be forced to scream it at the compiler.

vjvjvjvjghv 1 day ago

The dev should have the option to turn it off but I think that removing a lot of undefined and non deterministic behavior would be a good thing. When I did C++ I initialized everything and when there was a bug it could usually be reproduced. There are a few cases where it makes sense performance wise to not initialize but those cases are very small compared to most other code where undefined behavior causes a ton of intermittent bugs.

tonyhart7 1 day ago

"If the programmer wants to have uninitialized memory -- that is her business."

idk, seems like years of academic effort and research wasted if we do the way C++ do it

flavio81 19 hours ago

>I want C++ do exactly and only what the programmer specifies

Good luck with that.