Live data from Hacker News

Initialization in C++ is Seriously Bonkers

mikelui.io

1–10 of 130 posts

Re: Initialization in C++ is Seriously Bonkers

#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 is backwards. 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.

The fact 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. Now, it may not be a good feature, and modern language designs have omitted it (by, let's remember, relying on much better modern compilers to elide all the extra code that would otherwise have been needed to zero out a stack frame!).

But it's got nothing to do with the syntax of the language. You can rely on .bss being zero in assembly, and similarly be surprised that stack memory is going to have junk in it.

Re: Initialization in C++ is Seriously Bonkers

#3
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…

I always think C/C++ is not a good first language to teach, because you need to understand some general concepts about computer systems before diving in. Probably more than half of the beginners in their first C class give up when handling pointers/arrays - it's not because the concept is hard, but because they have no idea what the "memory" in the computer actually is and how it works. You're left with a naive analogy of home addresses and phone numbers, but it really doesn't give pointers justice (especially when dealing with arrays and dynamic memory!) Every student learning C should have a basic idea about the stack and the heap, how function calls work, and how assembly code is executed, in order to get the full picture.

Anyways, the problem C++ has for beginners is that the language tries to obscure the already hard to understand low-level behavior with high-level concepts (to be fair, that is the language's ultimate goal: to provide a high-level abstraction for low-level code.) So maybe good for your second/third language, but definitely not your first.

Re: Initialization in C++ is Seriously Bonkers

#4
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 .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 suboptimal code for:

const int i = 0;

Re: Initialization in C++ is Seriously Bonkers

#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 reasonable.

In the case of:

a1: There is no initializer list in the variable declaration, so ctor 2 is called.

a2: An empty initializer list should reasonably behave like a default constructor, and a default constructor should be more efficient than processing an initializer_list, so ctor 2 is called. In general, the constructor with the matching number of arguments and correct types is preferred over initializer_list constructors. Makes sense, being able to specialize on number and type of arguments is more powerful than a design where a single initializer_list ctor invalidates all other ctors.

a3: No list, ctor 2 is called.

a4: Non-empty init list and no specialized non-init-list ctor, so ctor 1 is called.

a5: Several-variable init list and no overriding 3-variable constructor with matching types, therefore ctor 1 is called.

Complex? Maybe, but that's what you get with C++: very fine control of program semantics, benefit being expressive libraries. No other language fills this niche that I'm aware of.

I agree that C++ isn't a good language to teach in a CS 101 class. But no other single language is good either. The goal of CS 101 is to not make students give up before they get hooked, and that can happen because the material is too challenging or not challenging enough. For people in the former category, give them a scripting language and visual feedback, like Lua + Garrysmod. For the latter, give them assembly, haskell, C, C++ (teaching it like "C with templates" not "C with classes").

Re: Initialization in C++ is Seriously Bonkers

#6
post #3
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…

I always think C/C++ is not a good first language to teach, because you need to understand some general concepts about computer systems before diving in. Probably more than half of the beginners in their first C class give up when handling pointers/arrays - it's not because the concept is hard, but because they have no idea what the "memory" in the computer actually is and how it works. You're left with a naive analo…

> I always think C/C++ is not a good first language to teach, because you need to understand some general concepts about computer systems before diving in.

Some believe that it's important to teach those things about computer systems first. To anyone who knows how the machine works it's pretty obvious why a primitive stack variable is uninitialized: initializing them would cost a store which would in most cases be pointless. People use C and C++ because they want all of the performance the machine has to offer, and usually more. Stuffing the program full of immediate value loads and stores would make it huge and slow. C++ is already cursed with enough pointless stores, for example initializing the buffer of a string just after resize and just before copying something else into the same memory. We don't need more of these things.

The author then goes on to complain at length about {} initializers in C++11, which everyone recognizes as problematic, and which has been partially fixed in C++14. This has basically nothing to do with the first part of the article.

Re: Initialization in C++ is Seriously Bonkers

#7
post #4
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 .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 OS program loader is who allocates pages to .bss and initializes them to zero. In the case of an OS, who would do that initialization? At best it would be the bootloader. Initialization during kernel_init() before using any globals is acceptable too.

Re: Initialization in C++ is Seriously Bonkers

#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.

Re: Initialization in C++ is Seriously Bonkers

#9
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…

> Complex? Yes, but that's what you get with C++:

Congrats on successfully summarizing the complaint.

It's not mysterious, but it's gratuitously complex. And this is only variable initialization.

Re: Initialization in C++ is Seriously Bonkers

#10
post #9
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…

> Complex? Yes, but that's what you get with C++: Congrats on successfully summarizing the complaint. It's not mysterious, but it's gratuitously complex. And this is only variable initialization.

Indeed.

If just setting integers is this complicated, what do you expect to happen when you are trying to solve real problems?

Post reply on HN