Live data from Hacker News

Initialization in C++ is Seriously Bonkers

mikelui.io

71–80 of 130 posts

Re: Initialization in C++ is Seriously Bonkers

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

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

But those typedefs almost always (in my experience) contain some indication of at the very least an abbreviation of the type and some hints as to whether it's a pointer or not.

That's a lot better to go on than "auto".

Re: Initialization in C++ is Seriously Bonkers

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

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

Yes, to be clear I wasn't accusing Rust code of having this particular problem, I was just using it as an example of a modern language where in my opinion there's a bit of an over-emphasis on brevity in terms of writing the code, as opposed to reading/understanding it and maintaining it, which I feel for long-term large projects, I'm not convinced is a total win.

I could have easily used Go or Swift as examples instead.

And to be clear, these new languages are in general improving things a lot, but I just worry there's an over-emphasis on "being able to do a lot of complex stuff which very few syntax / characters", which I don't really fully agree with (at least for large complex long-term projects).

That's not to say I'm right, but in my experience of programming over 15 years in everything from ADA, C, C++ to Java and Python, at least on large projects, the speed at which code was created was very rarely that important. Getting it right, bug-free and performant was generally much more important. In some cases newer more-condensed syntax can definitely help, but in others, it can cause trouble.

Re: Initialization in C++ is Seriously Bonkers

#73
post #58

Earlier quoted context omitted.

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

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

Not at all. I also believe that we shouldn't hide logic bugs, but the problem with this class of bugs is how they are hard to catch: forcing the initialization can at least make the behavior more consistent across execution of the same program (avoid the rare sequence of condition that will clobber the value the right way before you use it). For some specific application this may be an OK tradeoff for release builds.

But to clarify why I posted this, I was just trying add one piece of data to this part of the thread of discussion

>> " With modern static analysis, there's probably no performance benefit to not initializing stack variables that are read before they're written?" >"Implicit default initialization will never be 100% as efficient as simply not requiring initialization"

Actually we don't know the exact impact, it is likely codebase dependent, but this patch in clang will allow to experiment with various tradeoffs.

> where compilers fail to notify the programmer that they statically detected a logic bug

Compilers (at least clang) won't detect a logic bug without noticing the programmer. You have warnings for this.

The optimize just "assumes" that there is no logic bug but can't reason about the logic:

{ int a = 1; foo(&a); } int b; bar(&b);

Can I optimize toward:

int a = 1; foo(&a); bar(&a);

If we assume that there is no logic bug, then it seems like a valid transformation to me. But if bar reads it parameter before writing to it, then this optimization makes foo impacting bar.

Re: Initialization in C++ is Seriously Bonkers

#74
post #38

Earlier quoted context omitted.

It’s the C runtime that zeros it, not the OS. That’s my main point. The OS may initialize too, but that is outside the standard.

On oddball platforms it might be (though I think there's some quibbling as to whether the C runtime in such an environment is really distinct form "the OS"). It's not on Linux. The .bss segment becomes an anonymous mmap which is zeroed by the kernel when first accessed. Glibc never touches it. (Edit to correct: obviously glibc "touches" .bss because it has its own static variables. But there's no "zero .bss" step in…

./libgcc/config/nds32/crtzero.S

    .L_bss_init:
        ! clear BSS, this process can be 4 time faster if data is 4 byte aligned
        ! if so, use swi.p instead of sbi.p
        ! the related stuff are defined in linker script
        la  $r0, _edata     ! get the starting addr of bss
        la  $r2, _end       ! get ending addr of bss
        beq $r0, $r2, .L_call_main  ! if no bss just do nothing
        movi    $r1, 0          ! should be cleared to 0
    .L_clear_bss:
        sbi.p   $r1, [$r0], 1       ! Set 0 to bss
        bne $r0, $r2, .L_clear_bss  ! Still bytes left to set

Re: Initialization in C++ is Seriously Bonkers

#75
post #42

Earlier quoted context omitted.

I learnt C as a first language, and those computer sytems concept were explained as we go. It's not that hard to understand what memory is and that variables values are stored there, and I've had no problem with pointers. And the big advantage is that when you understand those concept and pointers, there's no magic in other languages (value/reference parameters, objects, functions as first-class citizens)

Totally agree. Knowing C and a little assembly takes out the magic from other higher level languages. That's a good thing.

Monads are still a little magical though.

Re: Initialization in C++ is Seriously Bonkers

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

In the next sentence I say:

> variables must always be initialized before they’re used.

Also I believe I’m quoting close to the standard there about indeterminate value.

I stayed away from using the term “undefined behavior” because I’ve had a lot of problems in the past with students believing undefined behavior means “but it works if they ran a test with a particular compiler version and flags and didn’t see any problems”. No matter how I try to equivocate undefined behavior with invalid code, it has trouble sticking. This is a understandable perspective built from starting at interpreted languages that immediately notify of any runtime errors and otherwise don’t have undefined behavior.

Re: Initialization in C++ is Seriously Bonkers

#77
post #70

Earlier quoted context omitted.

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

I agree there's a lot of value in understanding hardware/OSs/etc, but it's no substitute for having a solid understanding of C in general. C has much to say on undefined behaviour, and there are no shortcuts - you just have to have a good grasp of the language's dark corners.

(Aside: I believe ++i++; is no longer UB in the latest version of the language, but used to be.)

On the particular topic of initialization in C/C++, I go with the rule of thumb of be as explicit as possible.

Beyond that, I'm not afraid to assign a marker value to a local only to overwrite it soon afterwards. I save myself endless trouble in case my code is buggy, and if it's not, the compiler is likely to elide the first assignment entirely.

Re: Initialization in C++ is Seriously Bonkers

#78
post #73

Earlier quoted context omitted.

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

> Doesn't seem to me like a statement that variables should be implicitly initialized. Not at all. I also believe that we shouldn't hide logic bugs, but the problem with this class of bugs is how they are hard to catch: forcing the initialization can at least make the behavior more consistent across execution of the same program (avoid the rare sequence of condition that will clobber the value the right way before yo…

Thanks, that's insightful!

Re: Initialization in C++ is Seriously Bonkers

#79
post #76

Earlier quoted context omitted.

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

In the next sentence I say: > variables must always be initialized before they’re used. Also I believe I’m quoting close to the standard there about indeterminate value. I stayed away from using the term “undefined behavior” because I’ve had a lot of problems in the past with students believing undefined behavior means “but it works if they ran a test with a particular compiler version and flags and didn’t see any pr…

Your first points are well taken. From a quick googling you're right about the way the spec phrases it. It is, of course, terribly precise about under what circumstances UB occurs - https://stackoverflow.com/a/23429477/

> I stayed away from using the term “undefined behavior” because I’ve had a lot of problems in the past with students believing undefined behavior means “but it works [...]

Seems to me that developing a due terror of UB is vital to having a basic understanding of C as a programming language * , and beyond that, it's vital to appreciating what C is.

As well as being a considerable practical headache (it's not a compiler bug, it's UB going haywire), it's one of the major differences between C and, say, Java (alongside the way C types are not portable, etc). I'd say it deserves some emphasis as a basic principle.

* I suspect some theorists would contend that, strictly speaking, C programs aren't programs, and C isn't a programming language. Programs are, theoretically, meant to unambiguously map inputs to outputs. C is not unambiguous. But, needless to say, I digress.

Re: Initialization in C++ is Seriously Bonkers

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

Considering that a vast amount of extremely important software and large projects use C++, I would say it solves real problems nicely. You can get pedantic about features of any language if you want to.
Post reply on HN