Skip to content(if available)orjump to list(if available)

Initialization in C++ is bonkers (2017)

shadowdev1

Heh, low comments on C++ posts now. A sign of the times. My two cents anyway.

I've been using C++ for a decade. Of all the warts, they all pale in comparison to the default initialization behavior. After seeing thousands of bugs, the worst have essentially been caused by cascading surprises from initialization UB from newbies. The easiest, simplest fix is simply to default initialize with a value. That's what everyone expects anyway. Use Python mentality here. Make UB initialization an EXPLICIT choice with a keyword. If you want garbage in your variable and you think that's okay for a tiny performance improvement, then you should have to say it with a keyword. Don't just leave it up to some tiny invisible visual detail no one looks at when they skim code (the missing parens). It really is that easy for the language designers. When thinking about backward compatibility... keep in mind that the old code was arguably already broken. There's not a good reason to keep letting it compile. Add a flag for --unsafe-initialization-i-cause-trouble if you really want to keep it.

C++, I still love you. We're still friends.

josefx

> keep in mind that the old code was arguably already broken

The code is only broken if the data is used before anything is written to it. A lot of uninitialized data is wrapped by APIs that prevent reading before something was written to it, for example the capacity of a standard vector, buffers for IO should only access bytes that where already stored in them. I have also worked with a significant number of APIs that expect a large array of POD types and then tell you how many entries they filled.

> for a tiny performance improvement

Given how Linux allocates memory pages only if they are touched and many containers intentionally grow faster then they are used? It reduces the amount of page faults and memory use significantly if only the used objects get touched at all.

juliangmp

> When thinking about backward compatibility... keep in mind that the old code was arguably already broken. There's not a good reason to keep letting it compile.

Oh how I wish the C++ committee and compiler authors would adopt this way of thinking... Sadly we're dealing with an ecosystem where you have to curate your compiler options and also use clang-tidy to avoid even the simplest mistakes :/

Like its insane to me how Wconversion is not the default behavior.

zahlman

>Oh how I wish the C++ committee and compiler authors would adopt this way of thinking

Many different committees, organizations etc. could benefit, IMO.

loeg

Compilers should add this as a non-standard extension, right? -ftrivial-auto-var-init=zero is a partial solution to a related problem, but it seems like they could just... not have UB here. It can't be that helpful for optimization.

Matheus28

Yes but it’s not portable. If zero initialization were the default and you had to opt-in with [[uninitialized]] for each declaration it’d be a lot safer. Unfortunately I don’t think that will happen any time soon.

tialaramex

You probably don't want zero initialization if you can help it.

Ideally, what you want is what Rust and many modern languages do: programs which don't explain what they wanted don't compile, so, when you forget to initialize that won't compile. A Rust programmer can write "Don't initialize this 1024 byte buffer" and get the same (absence of) code but it's a hell of a mouthful - so they won't do it by mistake.

The next best option, which is what C++ 26 will ship, is what they called "Erroneous Behaviour". Under EB it's defined as an error not to initialize something you use but it is also defined what happens so you can't have awful UB problems, typically it's something like the vendor specifies which bit pattern is written to an "unintialized" object and that's the pattern you will observe.

Why not zero? Unfortunately zero is too often a "magic" value in C and C++. It's the Unix root user, it's often an invalid or reserved state for things. So while zero may be faster in some cases, it's usually a bad choice and should be avoided.

loeg

I don't really care if it isn't portable. I only have to work with Clang, personally.

> If zero initialization were the default and you had to opt-in with [[uninitialized]] for each declaration it’d be a lot safer.

I support that, too. Just seems harder than getting a flag into Clang or GCC.

null

[deleted]

MichaelRo

>> Of all the warts, they all pale in comparison to the default initialization behavior.

Come on. That's nothing compared to the horrors that lay in manual memory management. Like I've never worked with a C++ based application that doesn't have crashes lurking all around, so bad that even a core dump leaves you clueless as to what's happening. Couple OOP involving hundreds of classes and 50 levels deep calls with 100s of threads and you're hating your life when trying to find the cause for yet another crash.

kaashif

50 levels deep? With some of the template metaprogramming I've seen, looking at just the types for just one level will not only fill your screen, but take up megabytes on disk...

nlehuen

Not to worry, there is a 278 page book about initialization in C++!

https://leanpub.com/cppinitbook

(I don't know whether it's good or not, I just find it fascinating that it exists)

bhk

Wow! Exhibit 1 for the prosecution.

kazinator

C++ doesn't have initiation hazing rituals, but initialization hazing rituals. (One of which is that book.)

nitrogen99

Well, authors are incentivized into writing long books. Having said that it obviously doesn't take away the fact that C++ init is indeed bonkers.

harry8

What would be the incentive for making this a long book? Couldn't be money.

jcelerier

It is actually. It's been shown that longer books make more sales as they are considered more trustworthy, so authors are incentivized to artificially drag them longer than they actually require

Analemma_

I imagine if I'd managed to actually memorize all of C++'s initialization rules, I'd probably have to write a book too just to get it all out, or I'd lose my sanity.

ts4z

This is a specialization of the general statement that C++ is bonkers.

gnabgib

Small discussion at the time (42 points, 6 comments) https://news.ycombinator.com/item?id=14532478

Related: Initialization in C++ is Seriously Bonkers (166 points, 2019, 126 points) https://news.ycombinator.com/item?id=18832311

kazinator

> This rule makes sense when you think about it

No, it is bonkers; stick to your consistent point, please.

These two should have exactly the same effect:

  bar() = default;       // inside class declaration

  bar::bar() = default;  // outside class declaration
The only difference between them should be analogous to the difference between an inline and non-inline function.

For instance, it might be that the latter one is slower than the former, because the compiler doesn't know from the class declaration that the default constructor is actually not user-defined but default. How it would work is that a non-inline definition is emitted, which dutifully performs the initialization, and that definition is actually called.

That's what non-bonkers might look like, in any case.

I.e. both examples are rewritten by the compiler into

  bar() { __default_init; }

  bar::bar() { __default_init; }
where __default_init is a fictitious place holder for the implementation's code generation strategy for doing that default initialization. It would behave the same way, other than being inlined in the one case and not in the other.

Another way that it could be non-bonkers is if default were simply not allowed outside of the class declaration.

  bar::bar() default;  // error, too late; class declared already!
Something that has no hope of working right and is easily detectable by syntax alone should be diagnosed. If default only works right when it is present at class declaration time, then ban it elsewhere.

e-dant

Let the language die, hope it goes quicker than cobol.

trealira

C++ is not going anywhere. It's even still used in gamedev to make new games. It's used in HPC and scientific computing. Windows applications often use it. And so on.

greesil

I don't think it's going anywhere, too much existing code that's still useful. People STILL use Fortran 77 for goodness sake.

compiler-guy

https://www.phoronix.com/news/GCC-15-Merges-COBOL

COBOL Language Frontend Merged For GCC 15 Compiler Written by Michael Larabel in GNU on 11 March 2025 at 06:22 AM EDT. 33 Comments

bdangubic

“quicker than cobol” means it will die in the next 100 years (maybe) :)

gosub100

COBOL is alive and well. Why would a company rewrite a codebase that has decades of error free functionality? What do they get?

cheema33

> Why would a company rewrite a codebase that has decades of error free functionality? What do they get?

All well and good if it is something you do not have to modify/maintain on a regular basis. But, if you do, then the ROI on replacing it might be high, depending on how much pain it is to keep maintaining it.

We have an old web app written in asp.net web forms. It mostly works. But we have to maintain it and add functionality to it. And that is where the pain is. We've been doing it for a few years but the amount of pain it is to work on it is quite high. So we are slowly replacing it. One page at a time.

gosub100

the insurance companies running COBOL don't care. it's cheaper to pay a cowboy $X00,000/yr to keep the gravy dispenser running than trying to modify it. by definition, this is code that's been in use for decades. Why change it?

jimbob45

I suspect the committee agrees with you. I think they’ve anticipated a competitor coming to kill C++ for two decades now and see themselves as keeping C++ on life support for those who need it.

It’s shameful that there’s no good successor to C++ outside of C# and Java (and those really aren’t successors). Carbon was the closest we came and Google seems to have preemptively dropped it.

wffurr

The latest Carbon newsletter is here, from March: https://github.com/carbon-language/carbon-lang/discussions/5...

compiler-guy

Carbon is still quite active.

jimbob45

The addition of a safety design is a shift in our milestones for v0.1, and you can see the difference here. Both of these are fundamental parts of v0.1, and will take long enough that the earliest date for v0.1 is pushed out to the end of 2026

Look, no one is more excited than me for this, but this is reaching Star Citizen levels of delays.

nyarlathotep_

Aside, but the author of this blog is the author of https://nostarch.com/building-a-debugger

A wonderful exploration of an underexplored topic--I've pre-ordered the hard copy and have been following along with the e-book in the interim.

markhahn

Most of that actually just makes sense if you approach it from the historic,low-level, minimalist direction. But maybe if you're coming from some other, higher-comfort language...

frollogaston

Coming from C, none of this made sense to me. Wut is `foo() = default;`? If you want a default value of 0, why isn't it just

  struct foo {
    int a = 0;
  };
In Python, which is higher-level ofc, I still have to do `foo = 0`, nice and clear.

Maxatar

`foo() = default;` is an explicit way to generate a default constructor for `foo`. The default constructor works by recursively calling the default constructors for all class instance fields. In C++ there are a bunch of rules about when a class has a default constructor or not, but by explicitly declaring one you are guaranteed to have it so long as all your class instance fields have default constructors.

Your example of having a field called `a` that is initialized to 0 is perfectly valid C++ as well but it's not the same as an explicitly declared default constructor.

zabzonk

> If you want a default value of 0, why isn't it ...

It is.

null

[deleted]

beached_whale

And for the most part it does what you expect.

null

[deleted]