6 ms·
RFC: Automatic variable initialization
- captainmuon 8y agoIt's a pity the flag -ftrivial-auto-var-init=zero is eventually going to go away (there is -enable-trivial-auto-var-init-zero-knowing-it-will-be-removed-from-clang). I understand their motive, but it would be great to use that flag and others like -fno-strict-aliasing etc. to make a "safe and friendly C" dialect. I.e. turning undefined behavior into "obvious" behavior when possible.
- dlivingston 8y agoI thought you writing `-enable-trivial-auto-var-init-zero-knowning-it-will-be-removed-from-clang` was just satire. Nope. A little humorous that it's a real flag. https://reviews.llvm.org/D54604?id=174471 https://reviews.llvm.org/D54604?id=174471
- rurban 8y agoSure, but why the trivial prefix? Doesn't sound too ensuring then.
- saagarjha 8y agoI'm assuming the "trivial" refers to "trivial" types.
- loeg 8y agoSure, but it's unclear what the benefit of leaving auto C++ objects uninitialized is.
- eridius 8y agoIIRC, auto C++ objects aren't uninitialized, they're default-initialized, but said default-initialization may leave them with uninitialized fields. I would hope that this new automatic variable initialization would also apply to those fields of default-initialized auto C++ objects.
- kazinator 8y agoBuilt-in types like int are also "object"; only C++ class objects can have constructors that initialize them.
- olliej 8y agoAuto declarations don’t mean uninitialised, they get default initialisation, which for many types means “undefined”.
- loeg 8y agoI should have been more clear. What's the benefit of leaving automatic storage C++ object memory uninitialized?
- saagarjha 8y agoIt's fast?
- loeg 8y agoThe proposal would already accepti a performance tradeoff to initialize memory of uninitialized "trivial" variables. I'm not sure why you would want to draw a line in the sand at trivial variables only. What makes non-trivial uninitialized object memory higher penalty or lower risk?
- saagarjha 8y agoEven if projects choose not to adopt this (~3% performance impact might be too much?) I'd love to have this as a sort of "lightweight address/UB sanitizer" to check for uninitialized variables.
- AndyKelley 8y agoIt actually accomplishes the opposite; hiding uninitialized values from tools such as Valgrind. If you're trying to find uninitialized variables then you would specifically not enable this flag so that the detection can work. This is why I intentionally leave variables uninitialized rather than put bogus initialization values. Example: int x; if (cond) { x = foo(); } else { x = bar(); } Some people when they see my code, have the urge to modify it so that x is initialized to 0 before the branches. But this hides bugs. If for example, I later made the if-else chain more complicated, and one of the branches failed to initialize `x`, better to find out with Valgrind than to have a hard-to-find-bug where an invalid value of 0 was used in an unexpected place. This would be a flag to enable on release builds; a bug mitigation technique rather than a debugging technique.
- gopalv 8y ago> Some people when they see my code, have the urge to modify it so that x is initialized to 0 before the branches. But this hides bugs. Something like Java's final would be useful in such a scenario. I write code which looks exactly like this, except I only do this for final variables - the compiler throws an error if I add a branch which doesn't explicitly set it.
- maxxxxx 8y ago" the compiler throws an error if I add a branch which doesn't explicitly set it." That's pretty useful.
- twic 8y agoIt is! It's called definite assignment: https://docs.oracle.com/javase/specs/jls/se10/html/jls-16.html https://docs.oracle.com/javase/specs/jls/se10/html/jls-16.ht... Java was my first language, so i took it for granted; i was alarmed when i found out that C and C++ don't have it. It's saved my bacon too many times to count. FWIW, Rust does have this rule; this code: fn show(x: usize) { let message; if x % 2 == 0 { message = "even"; } println!("{} is {}", x, message); } is rejected with error E0381: https://doc.rust-lang.org/stable/error-index.html#E0381 https://doc.rust-lang.org/stable/error-index.html#E0381
- kazinator 8y agoAlready in Lisp for decades: (let (x y z) (list x y z)) -> (nil nil nil). However, nil has a distinct type. Thus: (let (x) ;; not initialized ;; ... (when condition (setf x ...)) (numeric-code x)) ;; still blows up if condition was false In other words, this initialization doesn't create a big risk of hiding errors due to initialization with a correctly typed bogus value that could be inappropriate. nil is the empty list. The risk of a bug where a local variable holds an empty list that should have been initialized to some non-empty list seems low. nil is also Boolean false. The risk of a bug where a local Boolean variable was implicitly initialized to false, but should have been true, also seems low.