I didn't know you could do this:
int x = {}; // x == 0
Rect r = {}; // r == {0, 0, 0, 0}
Interesting read.
I understand the desire to maintain efficiency by leaving things uninitialized. I find it is definitely easier to debug if values are set to reasonable defaults, such as 0 for int. When I look at the contents of a value type and everything is default I know it was created but not fed data or all the data was default. If it contains random values I have to reason if the random data means something or if it is truly random.
Also when debugging, I prefer to get consistent results from uninitialized structs/classes by having default values. If the values are all random when uninitialized, different parts of the code base may flop between working and failing on each pass which I find harder to reason with than consistent results. The counterpoint is you have a bit better chance to become aware of bugs because an initialized default value may not cause noticeable problems upfront whereas a random value will sometimes cause a problem.
Since C++ defaults to not setting values to default, I think it makes the most sense to not artificially force this by creating constructors everywhere that do so. I do think this is one reason Java or C# code is easier to debug.
Guess that is all preference though.
-Brett
Yes, not everyone is a fan of uninitialized data. It can be less reproducible, and so can create confusing bugs. Though as you've stated, the random data can also reveal bugs, that a default initialized value would have hidden. On the plus side, the compiler is often able to warn about use of uninitialized data. It depends a bit on the complexity of the code flow though. Not all things can be warned about, though most of the common cases will be.
In the end, it's more about efficiency, and not doing work that's just going to be overwritten later by a late initialization. It might be the proper value is not known until other work is done first.
As for the {} initialization (https://en.cppreference.com/w/cpp/language/initialization) syntax, it will zero initialize values in many cases.
In particular, the empty {} can be used directly after a type in value initialization (https://en.cppreference.com/w/cpp/language/value_initialization). Value initialization states a number of rules for zero-initializing. One curious rule, is that it may first initialize to zero, and then do default initialization (https://en.cppreference.com/w/cpp/language/default_initialization). In the Notes section of default initialization, you'll find that some object may be default initialized to indeterminate values. That actually means they won't be initialized. An example is an int local variable (but not a global, static, or thread-local variable, which is zero initialized). Hence the clause about zero-initializing first in value initialization is really about zero-initializing values that would otherwise be uninitialized. So basically, the value initialization syntax will set integers to 0 and floating point values to 0.0.
In terms of the example above (note the equal sign), we actually have aggregate initialization (https://en.cppreference.com/w/cpp/language/aggregate_initialization). Aggregate initialization has a rule where if the initializer list is shorter than the number of members to initialize, it will use value initialization on the remaining members. Hence you also get the zero-initialization here.
Example:
Rect r = {1}; // r == {1, 0, 0, 0}
Don't have a lot of time for a proper response so I'll just put this out there.
Was reading the article and came across this line:
If you feel uncomfortable with this implementation, you’re letting your inner Java programmer get the better of you. Don’t. This is C++. We embrace the undefined.
No! No no no no no! This is exactly how horrifying bugs are allowed to exist. This flies in the face of defensive programming. To take the contrive example, I would write it as such:
class Rectangle
{
int x1 = 0, y1 = 0, x2 = 0, y2 = 0;
public:
Rectangle() = default;
};
Yes, I know that there are cost overheads to initializing values but we're not dealing with embedded systems most of the time that require this level of optimization, we're dealing with real-world programming and, perhaps more importantly, humans that are very much flawed and imperfect.
The argument could be raised "Well if you're using unititialized values in C or C++ you're not a competent programmer". I scoff at this notion as both elitist and ignoring one of the primary sources of glaring bugs in programs: simple mistakes that all developers make.
So no. Don't embrace terrible ideas that only made sense in the days of 1KB of memory. Use defensive programming techniques and that includes always ensuring that any value is in a valid state unless you have absolutely concrete reason to do otherwise.
Leeor doesn't embrace the undefined ;)
Slightly out of context, I guess this relates to the author's other statement:
the simple chain of reasoning described so far has less friends than you might think. And this is why I wrote this article.
You will probably meet a lot of resistance when trying to implement your default and move constructors this way.
For a counter point, consider the following code:
Rect lotsOfThem[50000000];
LoadRectDataFromFile(lotsOfThem);
Do you really want to default initialize them first? Will an optimizer be able to help you here? I think this is the real case those rules were designed for.
So no. Don't embrace terrible ideas that only made sense in the days of 1KB of memory. Use defensive programming techniques and that includes always ensuring that any value is in a valid state unless you have absolutely concrete reason to do otherwise.
I think this is a big part of why there's been such a proliferation of computer languages. You're right, we don't live in such a constrained world anymore, people more or less have realized that, and default initialization and defensive programming techniques can help prevent bugs and wasted programmer time. But then, considering the design of both core C++, and it's standard library, it might not be the best choice of language for people who value those things. As a corollary to that, C++ might not be the best choice of language for most new programming projects these days. It does have a bit of a niche with embedded software, device drivers, and low level systems code. Maybe throw in a few small, well contained, performance critical libraries. Outside of that, I don't see it used for much other than maintenance of legacy programs written before there was such wide choice. I wouldn't recommend it to a paying client for a new greenfield project that doesn't fit its niche.
... but luckily this is hobby programming here ;)