Live data from Hacker News

Initialization in C++ is Seriously Bonkers

mikelui.io

11–20 of 130 posts

Re: Initialization in C++ is Seriously Bonkers

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

You ended the quote early, and my sentence went beyond the article. I said:

> that's what you get with C++: very fine control of program semantics, benefit being expressive libraries.

It's not gratuitous because you can't remove much of it without losing power or expressiveness (and still remain a C).

Also, by complex I didn't mean complicated.

Re: Initialization in C++ is Seriously Bonkers

#13
> C++ is not a language I’d want to teach beginners. At no point in this post was there room for systems programming concepts, discourse on programming paradigms, computational-oriented problem solving methodologies, or fundamental algorithms.

This is a ridiculous argument. The entire point of the post was, as the author even noted, purely to deep dive into a rabbit hole, get super picky & pedantic about standards wording so that you can act surprised that copy constructors exist in C++ while it was completely glossed over in the identical C example of a struct copy initialization, and almost none of this is useful to know.

So don't fucking teach it and you'd have plenty of time to cover all that other stuff. Bam, problem solved. Ignore pre-C++11 entirely, and purely teach & use the new stuff which fixes all the complexity, and leave the rabbit hole for people that care about exploring the past.

Oh, and don't use standards wording because those are for compilers to use to implement the language, not for programmers to understand how to use it effectively. The only time it's ever useful to know the full definition of an aggregate type or how it has changed is when you want to write a blog post calling them crazy or complex. It's never useful to know when using the language. And if you have an object that cares to enforce it just

    static_assert(std::is_aggregate_v, "A isn't an aggregate type");
Tada, now the compiler will tell you if/when you violated the rule and you don't need to try and understand the full scope of the ruleset.

Re: Initialization in C++ is Seriously Bonkers

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

It's hard to imagine many situations where you need to give a name to the constant value 0. And think how "optimal" it would be if there were many and we had a read-only BSS! We could cheaply get a huuuge section full of constant zeroes.

I think you can in fact realize the idea in PECOFF, by the way. I still need to figure out some aspects to it these days (it seems a bit arcane and maybe Windows doesn't follow the spec very well). But in any case PECOFF has this notion "VirtualSize" (size of section in running program) and "SizeInFile" (size of the prefix of the section that should be filled with contents from the executable file). If SizeInFile is smaller than VirtualSize then the rest of the image gets filled with zeroes I think.

Re: Initialization in C++ is Seriously Bonkers

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

In embedded assemblers I have used (TMS34010), the BSS section is uninitialized when the program is loaded (I helped write the OS). When I wrote embedded C, the added C runtime code that executes (before main() is called) zeroes out the BSS section (the OS has nothing to do with it). In other words, it is the C runtime that is responsible for initializing, not the OS.

Re: Initialization in C++ is Seriously Bonkers

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

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

Yes, initializer list with empty initializer list should behave same as empty constructor, and if it doesn’t, it’s really bad style. However, if both are defined, then if you are constructing an object with empty initializer list, the initializer list constructor should be called with an empty list as an argument, simple as that. That’s very logical and sensible semantics, so obviously C++ had to choose something different.

Re: Initialization in C++ is Seriously Bonkers

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

In embedded assemblers I have used (TMS34010), the BSS section is uninitialized when the program is loaded (I helped write the OS). When I wrote embedded C, the added C runtime code that executes (before main() is called) zeroes out the BSS section (the OS has nothing to do with it). In other words, it is the C runtime that is responsible for initializing, not the OS.

I think you're the fourth person jumping in to quibble with my "bss is zeroed by the OS" statement by snarking about "Ah hah! But what if you YOU ARE the OS?!".

Yeah, I know. I live in that world too. I don't know that it's particularly relevant. The C standard is written to a norm of a Unix userspace environment, and that's clearly where the linked article is working.

Re: Initialization in C++ is Seriously Bonkers

#18
post #16
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…

> 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. Yes, initializer list with empty initializer list should behave same as empty constructor, and if it doesn’t, it’s really bad style. However, if both are defined, then if you are constructing an object with empty initializer l…

While it does sometimes seem like C++ does some things because of how much sense they don't make, I don't think this is one of those cases. Read the rest of the sentence you quoted and I think you'll find that the way C++ does it will make sense.

Re: Initialization in C++ is Seriously Bonkers

#19
post #10
post #9

Earlier quoted context omitted.

> 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?

The parsing details can be complicated while the end result can be simple. Consider the actual C++ example that would be taught & used in practice:

   struct A {
     int i = 0;
   }
   
   int main() {
     A a;
     std::cout 
Hey, look, done. And you only had to teach a single thing - default initialization. Which has an obvious & simple syntax. The int i is always initialized to 0, as intended, and it's in a single spot at the point of declaration.

Now try doing that in C. Oh, wait, you can't. The closest you can get is this mess:

   struct A {
     int i;
   } const default_A = {0};
   
   int main() {
     struct A a5 = default_A;
     printf("%d\n", a5.i);
   }
Which requires you to know that you can declare a type & an instance of that type in a single statement, why that const is where it is and why that's important here, how braced initialization rules work, that you need to always remember to manually initialize to your default_A, and that %d means 'int'. And the compiler won't help you with any of this except for the %d part if you get it wrong.

Re: Initialization in C++ is Seriously Bonkers

#20
post #10

Earlier quoted context omitted.

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

The parsing details can be complicated while the end result can be simple. Consider the actual C++ example that would be taught & used in practice: struct A { int i = 0; } int main() { A a; std::cout Hey, look, done. And you only had to teach a single thing - default initialization. Which has an obvious & simple syntax. The int i is always initialized to 0, as intended, and it's in a single spot at the point of decla…

> Which requires you to know that you can declare a type & an instance of that type in a single statement

    struct A {
        int i;
    };

    const struct A default_A = { 0 };
Why didn't you try the obvious simple thing first?

The whole undertaking is pointless in any case. Why would you need default values (i.e. templates for constructors) baked in? The only reasonable default value, sometimes, is all-zeroes (or all-ones...).

Now, constant data (i.e. things that contain more useful information than just "it's the default because a real value is missing" -- and that aren't copied around pointlessly) is another case, and C's plain old value initializer syntax (as demonstrated above) serves it perfectly well.

Post reply on HN