Live data from Hacker News

Initialization in C++ is Seriously Bonkers

mikelui.io

61–70 of 130 posts

Re: Initialization in C++ is Seriously Bonkers

#61
post #4

Earlier quoted context omitted.

> The .bss segment has been zeroed, for obvious reasons, since the advent of modern linkage. For your amusement: in the Linux kernel , at least on x86, .bss isn’t initialized when the kernel is loaded. Instead, the kernel memsets it to zero a little later. I don’t know why. Also, because all this stuff predates any concept of security, there is no read-only equivalent of .bss in most systems, meaning that you get sub…

The optimal code for const int i = 0; is for the compiler to inline its uses, and for there never to be any storage allocated at all. ;-)

That works unless you use &i somewhere.

Re: Initialization in C++ is Seriously Bonkers

#62
post #8
post #2

> [Why is a global variable zero?] Because i has static storage duration, it’s initialized to unsigned zero. Why, you ask? Because the standard says so. No, it's because i lives in an area allocated at the OS level, and OS has to have initialized that memory with something (otherwise you'd have a security bug). The .bss segment has been zeroed, for obvious reasons, since the advent of modern linkage. The explanation…

> No, it's because i lives in an area allocated at the OS level What OS? I don't have one. I have to link in init code to zero sections of ram before my embedded code runs. Sure, it got into the standard because some popular OSes like Unix zero initialized pages, but it's not a universal truth. The reason it's guaranteed in C is because of the spec.

Dear lord sounds like you got lost from comp.lang.c. How did it get into the spec? Because Unix did it that way. Just like gets made it into the spec. It’s not like that was some willful good design. The history of C and it’s standarization is inextricably ties to the history of Unix.

Re: Initialization in C++ is Seriously Bonkers

#63
post #58

Earlier quoted context omitted.

> With modern static analysis, there's probably no performance benefit to not initializing stack variables that are read before they're written? Not really relevant because that's a bug. But the common thinking "let's always default-initialize stack variables because the compiler will make it efficient anyway" is clearly "sufficiently smart compiler" thinking. Implicit default initialization will never be 100% as eff…

Note that clang just got a change to experiment with this: https://reviews.llvm.org/rL349442

Doesn't seem to me like a statement that variables should be implicitly initialized.

It seems like a workaround around insanity with respect to UB (where compilers fail to notify the programmer that they statically detected a logic bug, and instead go on with compiling, making crazy optimizations based on the wrong assumption that the logic bug was never there).

Re: Initialization in C++ is Seriously Bonkers

#64
post #51

Earlier quoted context omitted.

How so? My experience has been that it actually reduces net complexity, except in the case where you need to support different versions of the language in the same codebase. Take for example, `auto`, added in C++11. If you don't have to support C++98 or C++03, the use of `auto` significantly simplifies many workflows and is often strictly better with less mental overhead.

> Take for example, `auto`, added in C++11. If you don't have to support C++98 or C++03, the use of `auto` significantly simplifies many workflows and is often strictly better with less mental overhead. When writing code, yes, but in my experience, it can also make interpreting what code that overuses auto is doing (especially what variables are and what functions return) an awful lot harder in many situations, and y…

is there a specific case that the uint32_t helps understanding the logic of the code?

Re: Initialization in C++ is Seriously Bonkers

#65
post #2

> [Why is a global variable zero?] Because i has static storage duration, it’s initialized to unsigned zero. Why, you ask? Because the standard says so. No, it's because i lives in an area allocated at the OS level, and OS has to have initialized that memory with something (otherwise you'd have a security bug). The .bss segment has been zeroed, for obvious reasons, since the advent of modern linkage. The explanation…

> The reason that stack variables are UNinitialized is (contra the article which thinks it's because the programmer didn't put an initializer in the source code) that memory is on the stack, which is allocated internal to your program and in practice was used previously by some other call for some other purpose.

It is because the programmer didn't put an initializer into the source code. That's how the language is defined. What you are discussing is the underlying reason the language is defined that way. You are speaking past the author, not pointing out a mistake.

The blog post does contain a genuine error relating to this point, though: Any C programmer worth anything knows that this initializes i to an indeterminate value. This is wrong. Reading the variable does not simply give you an indeterminate value, it gives undefined behaviour (something the article never mentions, surprisingly).

> that stack variables are uninitialized by default is actually an intentional feature, not a bug, as it correctly expresses the behavior of the runtime environment

But it doesn't. Reading an uninitialized local variable gives undefined behaviour, which might not correspond to the behaviour of using any particular garbage value.

Anyway, the language is defined that way simply for performance reasons. The risk of undefined behaviour is a considerable downside but was deemed acceptable.

> But it's got nothing to do with the syntax of the language.

We're talking about the semantics of C. If C were defined such that static integer variables be initialized with 1 rather than 0, that's what would happen, no?

Re: Initialization in C++ is Seriously Bonkers

#66
post #51

Earlier quoted context omitted.

How so? My experience has been that it actually reduces net complexity, except in the case where you need to support different versions of the language in the same codebase. Take for example, `auto`, added in C++11. If you don't have to support C++98 or C++03, the use of `auto` significantly simplifies many workflows and is often strictly better with less mental overhead.

> Take for example, `auto`, added in C++11. If you don't have to support C++98 or C++03, the use of `auto` significantly simplifies many workflows and is often strictly better with less mental overhead. When writing code, yes, but in my experience, it can also make interpreting what code that overuses auto is doing (especially what variables are and what functions return) an awful lot harder in many situations, and y…

Rust actually deliberately requires types to be declared, expect inside function bodies. So function return types have to be explicit. The main reason is exactly your readability argument. (Of course it also makes type inference inside the function body easier).

Re: Initialization in C++ is Seriously Bonkers

#67
post #51

Earlier quoted context omitted.

How so? My experience has been that it actually reduces net complexity, except in the case where you need to support different versions of the language in the same codebase. Take for example, `auto`, added in C++11. If you don't have to support C++98 or C++03, the use of `auto` significantly simplifies many workflows and is often strictly better with less mental overhead.

> Take for example, `auto`, added in C++11. If you don't have to support C++98 or C++03, the use of `auto` significantly simplifies many workflows and is often strictly better with less mental overhead. When writing code, yes, but in my experience, it can also make interpreting what code that overuses auto is doing (especially what variables are and what functions return) an awful lot harder in many situations, and y…

Most pre-C++11 code I've seen that gets iterators from `begin()`, `end()`, and friends just typedef out their actual type anyways, so you the experience there is not that different from `auto`.

Re: Initialization in C++ is Seriously Bonkers

#68
post #5

In my view this author falls into the camp of people calling C++ a mess because it gives them too much control when they ask for it. One of his examples which he calls "The Abyss": #include struct A { A(std::initializer_list l) : i(2) {} A(int i = 1) : i(i) {} int i; }; int main() { A a1; A a2{}; A a3(3); A a4 = {5}; A a5{4, 3, 2}; std::cout which outputs: 1 1 3 2 2 he claims to be mysterious but is actually pretty r…

C++ initialization is such a convoluted mess that CppCon was able to have an entire hour dedicated to "The Nightmare of Initialization in C++".

https://www.youtube.com/watch?v=7DTlWPgX6zs

C++ has a rigorous standard. There is no rule that wasn't added for a reason. Nor are there lines of code with which you can specify which rule it must follow.

The path to hell is paved with good intentions. Just because each step is logical and defensible doesn't mean the end result isn't fire and brimstone.

I believe that good things are more than the sum of their parts. You often hear this with respect to creative works like movies or games. I think it also applies to source code, language design, and much more. The flipside is that bad things are less than the sum of their parts. I've shipped games that fall into this category. C++ initialization has a LOT of parts. And I would strongly argue the end result is less than the sum of those parts.

Re: Initialization in C++ is Seriously Bonkers

#69
post #64
post #51

Earlier quoted context omitted.

> Take for example, `auto`, added in C++11. If you don't have to support C++98 or C++03, the use of `auto` significantly simplifies many workflows and is often strictly better with less mental overhead. When writing code, yes, but in my experience, it can also make interpreting what code that overuses auto is doing (especially what variables are and what functions return) an awful lot harder in many situations, and y…

is there a specific case that the uint32_t helps understanding the logic of the code?

That was a contrived example (although I've often seen auto used instead of that or even bool which I personally think are total over-uses of auto).

But knowing if something is a base type, a reference, a (smart) pointer, or an expensive-to-copy class/struct is very important when writing high-performance efficient code. Being able to see this at-a-glance by the type in the code in my experience helps tremendously with understanding what the code's doing and the implications in terms of data passing / transfer and understanding how that section of code interacts with other parts or could be changed to do other things.

I also think it allows people to be a bit sloppy and not care what's going on (i.e. with regards to whether it's by-value or by reference, etc) as they don't fully need to understand the code, and again, in high-performance computing where you seriously care about processor cycles and memory allocations, this can make a big difference if you're not careful.

Re: Initialization in C++ is Seriously Bonkers

#70
post #2

> [Why is a global variable zero?] Because i has static storage duration, it’s initialized to unsigned zero. Why, you ask? Because the standard says so. No, it's because i lives in an area allocated at the OS level, and OS has to have initialized that memory with something (otherwise you'd have a security bug). The .bss segment has been zeroed, for obvious reasons, since the advent of modern linkage. The explanation…

> The reason that stack variables are UNinitialized is (contra the article which thinks it's because the programmer didn't put an initializer in the source code) that memory is on the stack, which is allocated internal to your program and in practice was used previously by some other call for some other purpose. It is because the programmer didn't put an initializer into the source code. That's how the language is de…

You're not wrong, but I think this is a case where knowing the reason for the rules is easier than remembering the actual rules. This is just from personal experience, but for me, remembering what is and isn't initialized in C++ seemed completely arbitrary and insane until I learned more about linking and process startup. YMMV of course.
Post reply on HN