Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

uninitialized build-in types

156 views
Skip to first unread message

flimfl...@gmail.com

unread,
Dec 16, 2015, 2:59:55 PM12/16/15
to
I've long wished C++ worked a bit like this:

int x; // initialized to zero in all scopes (not just global)

int y = std::undefined; // it's left uninitialized, only when I say so

struct Foo {
Foo() { }
Foo(std::undefined_t) : x_(std::undefined) { }
int x_;
};

struct Bar {
Bar() { }
int x_;
};


Foo foo; // foo.x_ is zero
Foo foo = std::undefined; // foo.x_ is undefined

Bar bar; // bar.x_ is zero
Bar bar = std::undefined; // compiler error

I know there's at least a few of us out there who would welcome this sort of thing. I also know there's massive opposition to this from really smart people, and so I want to learn from you. If I could understand why it's better for built-ins to be undefined by default rather than by request, it would be a great help to me.

Please keep in mind I'm asking for guidance completely separate from the issues of legacy code or precedent set by C. I understand many of those issues. I instead want to learn why it shouldn't be done even if C++ were being designed for the first time today. If I could get that through my thick head, I'd be very happy.

Here's something that may help understand part of where I'm hung up:

int x; // undefined
float x; // undefined
void* x; // undefined
std::vector<int> x; // well defined
std::string x; // well defined
std::shared_ptr<int> // well defined (empty shared_ptr)

In a perfect world, why should they be different?

I've read rationale that cites valgrind. I get why valgrind is great for catching uninitialized data bugs, but I'm not sure why it would matter to valgrind whether the lack of initialization was default or explicit.

Paavo Helde

unread,
Dec 16, 2015, 3:48:53 PM12/16/15
to
flimfl...@gmail.com wrote in
news:53836b9f-b59d-4e57...@googlegroups.com:
For comparison: in the D language all variables are initialized by
default. In particular, floating-point variables are default-initialized
to signalling NaN, that's a nice touch IMO!

To leave something uninitialized one has to specifically say it:

int x = void;

>
> I've read rationale that cites valgrind. I get why valgrind is great
> for catching uninitialized data bugs, but I'm not sure why it would
> matter to valgrind whether the lack of initialization was default or
> explicit.

It would make it impossible to catch some errors. E.g.

void InitializeXY(int& x, int y) {
x = 1;
y = 2;
}

int x, y;
InitializeXY(x, y);
// go on to use x,y

As of now, the compiler or a tool like valgrind will report the error,
but if the variable had been zero-initialized there would be no error to
detect.

My wishlist: zero overhead signalling NaN-s for integer types as well,
and use them as default initializers.

Cheers
Paavo

David Brown

unread,
Dec 16, 2015, 5:19:54 PM12/16/15
to
On 16/12/15 20:59, flimfl...@gmail.com wrote:> I've long wished C++
worked a bit like this:
>
> int x; // initialized to zero in all scopes (not just global)

As Stefan says, you mean "not just static". Everything with a fixed
address in memory is initialised to zero, or with the default
constructor, if you don't explicitly give an initialisation value.

Stack allocated objects, as well as anything with memory allocated by
"malloc" (as distinct from "new"), is uninitialised.

This is a /good/ thing. Normally, you would not declare your local
variable until you have something to put in it:

int foo() {
...
int x = bar();
...
}

You don't write:

int foo() {
int x;
...
x = bar();
...
}

That style is a left-over from C before C99, and is rarely what you want
in C++ code. The only exception is code like this :

int foo(int a) {
int x;
if (a >= 0) {
x = positive();
} else {
x = negative();
}
}

In such cases, having x zero'ed in advance would be inefficient.

And note that if you have a half-decent compiler and know how to use it,
you are in (almost) no danger of accidentally using an uninitialised
variable - the compiler will warn you if you make such a mistake. On
the other hand, if you use "int x = 0;" or had implicit initialisation
of local variables as part of the language (as you suggest), you would
lose that warning ability that helps spot mistakes in code.

So having local data uninitialised by default is a good thing.

>
> int y = std::undefined; // it's left uninitialized, only when I say so

You don't mean "undefined", you mean "unspecified" or "indeterminate".
In C++ (and C), when something is "undefined" the behaviour can do
/anything/, including launching nasal daemons. What you mean here is
that y should have a valid and legal value for its type, but you don't
care which particular value. This means it out be legal behaviour to
use it (but hopefully with a compiler warning) - if it were "undefined"
then the compiler could assume the code that uses it could never happen.

In particular, I would expect a variable initialised to an "unspecified"
or "indeterminate" value to retain its value, and not change it at
different times. So "x == x" would always be true. An "undefined"
value, on the other hand, /could/ change - "x == x" could sometimes be
true, and sometimes false.


Having a "std::indeterminate" or "std::unspecified" (or using D's syntax
of "void", which I think is more practical) would be a nice idea for
some code. For example, you might have code like this:

struct ValidValue {
bool valid;
double value;
ValidValue(valid_, value_) : valid(valid_), value(value_) {};
};

ValidValue squareroot(double x) {
if (x >= 0) {
return ValidValue(true, sqrt(x));
} else {
return ValidValue(false, std::unspecified);
}
}

Initialising to "void" or "std::unspecified" would also be useful for
static and global data at times (perhaps particularly for embedded systems).


>
> struct Foo {
> Foo() { }
> Foo(std::undefined_t) : x_(std::undefined) { }
> int x_;
> };
>
> struct Bar {
> Bar() { }
> int x_;
> };
>
>
> Foo foo; // foo.x_ is zero
> Foo foo = std::undefined; // foo.x_ is undefined
>
> Bar bar; // bar.x_ is zero
> Bar bar = std::undefined; // compiler error
>
> I know there's at least a few of us out there who would welcome this
> sort of thing.

I think people who want locals to be zero-initialised by default haven't
thought things through well enough.

Having a way to explicitly declare something as uninitialised or
unspecified would be useful, however. It is a different concept.

> I also know there's massive opposition to this from
> really smart people, and so I want to learn from you. If I could
> understand why it's better for built-ins to be undefined by default
> rather than by request, it would be a great help to me.

Hopefully what I wrote above will be helpful to you.

>
> Please keep in mind I'm asking for guidance completely separate from
> the issues of legacy code or precedent set by C. I understand many of
> those issues. I instead want to learn why it shouldn't be done even if
> C++ were being designed for the first time today. If I could get that
> through my thick head, I'd be very happy.
>
> Here's something that may help understand part of where I'm hung up:
>
> int x; // undefined
> float x; // undefined
> void* x; // undefined
> std::vector<int> x; // well defined
> std::string x; // well defined
> std::shared_ptr<int> // well defined (empty shared_ptr)
>
> In a perfect world, why should they be different?

Objects often have an invariant that defines part of their structure -
it should not be easy in the language to create an object that does not
have that invariant. Part of the constructor's job is to establish the
invariant (indeed, for a default constructor that is often its only job)
- thus constructors need to be called on all objects. POD types like
"int" have no invariant, so there is no initialisation needed to make
the type a consistent member of that type.

Note that a default constructor does not have to initialise all members
of the object - only those that are needed to establish the invariant.

(I don't know whether "EnumClass e;" forces "e" to be an element of the
enum class, or if it is left indeterminate.)

flimfl...@gmail.com

unread,
Dec 16, 2015, 6:31:29 PM12/16/15
to

> As Stefan says, you mean "not just static".

My mistake - you're right. I sometimes conflate "global" and "static".


> This is a /good/ thing. Normally, you would not declare your local
> variable until you have something to put in it:
>
> int foo() {
> ...
> int x = bar();
> ...
> }
>
> You don't write:
>
> int foo() {
> int x;
> ...
> x = bar();
> ...
> }

Those cases have never bothered me. What makes me want different behavior in C++ is this:

In Gizmo.h:

class Gizmo {
public:
Gizmo();
... blah blah
private:
int x_; // I just added this member
};

In Gizmo.cpp:

Gizmo::Gizmo() :
x_(0) // and I have to go far away and do this too
{
}

and I still haven't done anything with x_ yet, which happens in other code that is similarly not next to declaration or initialization. C++11 allows me to do "int x_ = 0;" in the class declaration, but I can still forget, and it's still a different requirement on me than if x_ had been an std::vector<int>, or had static storage.


> And note that if you have a half-decent compiler and know how to use it,
> you are in (almost) no danger of accidentally using an uninitialised
> variable - the compiler will warn you if you make such a mistake. On
> the other hand, if you use "int x = 0;" or had implicit initialisation
> of local variables as part of the language (as you suggest), you would
> lose that warning ability that helps spot mistakes in code.

I do see these warnings a lot when the declaration, lack of initialization, and usage are all together. I've never seen such a warning when the data I forgot to initialize was a class member variable. Is that even possible? I use msvc, clang, ghs, armcc, codewarrior, and sn on a regular basis and I can't remember any analysis picking up on this type of mistake with uninitialized members.


> You don't mean "undefined", you mean "unspecified" or "indeterminate".

Sorry - you're right again. I sometimes conflate undefined and unspecified. This is even worse than global/static. Very bad of me.

> Having a "std::indeterminate" or "std::unspecified" (or using D's syntax
> of "void", which I think is more practical) would be a nice idea for
> some code. For example, you might have code like this:

I would really like this, wow. I actually considered 'void' too, but thought it might have ambiguity problems (I'm not qualified to know I think, so I resorted to something like std::nullptr_t). As long as using 'void' doesn't restrict me from using it with user-defined types too. I feel I'd sometimes want an un-initializing constructor, distinct from the default constructor.

> Objects often have an invariant that defines part of their structure -
> it should not be easy in the language to create an object that does not
> have that invariant. Part of the constructor's job is to establish the
> invariant (indeed, for a default constructor that is often its only job)
> - thus constructors need to be called on all objects. POD types like
> "int" have no invariant, so there is no initialisation needed to make
> the type a consistent member of that type.
>
> Note that a default constructor does not have to initialise all members
> of the object - only those that are needed to establish the invariant.

Hmmm, but with that rational, std::vector<int>'s default constructor could just as well decide to put 5 ints into the vector. That would satisfy it's invariants. But it doesn't. It puts zero ints in there, and we'd all be mad if it didn't. Still, you may not want zero - you may want it to have 10 ints each initialzied to 77 - and you have to ask for that or accept a well specified default state. I often find myself wishing the built-in types worked this way, almost always when adding new variables to classes.

Ian Collins

unread,
Dec 16, 2015, 6:47:28 PM12/16/15
to
flimfl...@gmail.com wrote:
> David Brown wrote:

[attribution replaced, please don't snip them!]

> and I still haven't done anything with x_ yet, which happens in other
> code that is similarly not next to declaration or initialization.
> C++11 allows me to do "int x_ = 0;" in the class declaration, but I
> can still forget, and it's still a different requirement on me than
> if x_ had been an std::vector<int>, or had static storage.
>
>
>> And note that if you have a half-decent compiler and know how to
>> use it, you are in (almost) no danger of accidentally using an
>> uninitialised variable - the compiler will warn you if you make
>> such a mistake. On the other hand, if you use "int x = 0;" or had
>> implicit initialisation of local variables as part of the language
>> (as you suggest), you would lose that warning ability that helps
>> spot mistakes in code.
>
> I do see these warnings a lot when the declaration, lack of
> initialization, and usage are all together. I've never seen such a
> warning when the data I forgot to initialize was a class member
> variable. Is that even possible? I use msvc, clang, ghs, armcc,
> codewarrior, and sn on a regular basis and I can't remember any
> analysis picking up on this type of mistake with uninitialized
> members.

That would be a difficult case to spot (except maybe in a constructor)
because the compiler can't really tell if the member variable has been
initialised before it used in another member function.

--
Ian Collins

David Brown

unread,
Dec 16, 2015, 7:00:03 PM12/16/15
to
Ask yourself /why/ you are adding x_ to the class. What is it doing?
How does it affect the behaviour of the class? And in particular, how
does it affect the class's invariant? If it has no effect on the
invariant, it doesn't matter how it is initialised. But if it /does/
have a part to play, as one would normally expect, then you need to
initialise it correctly. Of course that means editing the constructor -
adding the member to the class definition is only half the job.

If the compiler always initialised it to 0, then you would /still/ have
to look through the constructor, and think through the process - is 0 an
appropriate initial value here? Having the compiler initialise it to 0
saves you a negligible amount of time - it's a few seconds work to add
the x_(0) to the constructor. Most of the time and effort is thinking
about it - and you must do that anyway. Having the compiler make a
default that is sometimes appropriate risks letting you get away with
not thinking - and that's a bad thing.

>
>> And note that if you have a half-decent compiler and know how to use it,
>> you are in (almost) no danger of accidentally using an uninitialised
>> variable - the compiler will warn you if you make such a mistake. On
>> the other hand, if you use "int x = 0;" or had implicit initialisation
>> of local variables as part of the language (as you suggest), you would
>> lose that warning ability that helps spot mistakes in code.
>

> I do see these warnings a lot when the declaration, lack of
> initialization, and usage are all together. I've never seen such a
> warning when the data I forgot to initialize was a class member
> variable. Is that even possible? I use msvc, clang, ghs, armcc,
> codewarrior, and sn on a regular basis and I can't remember any analysis
> picking up on this type of mistake with uninitialized members.
>

If you see these warnings a lot, your coding practice is bad. These
warnings show that you are doing something wrong. There are good for
catching the occasional typo or glip, but if you get them often you
should think about how you are writing your code.

The compiler won't be able to guess about initialisation across compile
units (it might be able to do it with link-time optimisation). It can
only hope to see the issue if you made your constructors inline along
with the class definition.

And note that there is nothing inherently wrong with leaving a variable
or member uninitialised - it is only attempting to read it before
initialisation that is wrong.

>
>> You don't mean "undefined", you mean "unspecified" or "indeterminate".
>
> Sorry - you're right again. I sometimes conflate undefined and
> unspecified. This is even worse than global/static. Very bad of me.

It's an easy mistake to make - but I think the distinction is important
here, and can make things clearer for you.

>
>> Having a "std::indeterminate" or "std::unspecified" (or using D's syntax
>> of "void", which I think is more practical) would be a nice idea for
>> some code. For example, you might have code like this:
>
> I would really like this, wow. I actually considered 'void' too, but
> thought it might have ambiguity problems (I'm not qualified to know I
> think, so I resorted to something like std::nullptr_t). As long as using
> 'void' doesn't restrict me from using it with user-defined types too. I
> feel I'd sometimes want an un-initializing constructor, distinct from
> the default constructor.

Apparently D can use "void" like this (I have no actual experience with
D, just a little knowledge).

It is possible to make an approximate std::indeterminate implementation,
at least using compiler-specific code, but doing so properly (in a way
that gives the compiler maximal freedom) would take compiler support.

>
>> Objects often have an invariant that defines part of their structure -
>> it should not be easy in the language to create an object that does not
>> have that invariant. Part of the constructor's job is to establish the
>> invariant (indeed, for a default constructor that is often its only job)
>> - thus constructors need to be called on all objects. POD types like
>> "int" have no invariant, so there is no initialisation needed to make
>> the type a consistent member of that type.
>>
>> Note that a default constructor does not have to initialise all members
>> of the object - only those that are needed to establish the invariant.
>
> Hmmm, but with that rational, std::vector<int>'s default constructor
> could just as well decide to put 5 ints into the vector. That would
> satisfy it's invariants. But it doesn't. It puts zero ints in
> there, and we'd all be mad if it didn't. Still, you may not want
> zero - you may want it to have 10 ints each initialzied to 77 - and
> you have to ask for that or accept a well specified default state. I
> often find myself wishing the built-in types worked this way, almost
> always when adding new variables to classes.
>

Putting 5 ints into std::vector<int> would be a reasonable default
constructor - the main point is to make it consistent according to the
class's invariant. But it turns out that initialising the vector to
empty is the easiest and most efficient way to establish the invariant,
and it is convenient for everyone. So it is specified this way in the
standard - and we could complain if it didn't follow that standard.

However, there is nothing to guarantee that its /capacity/ is 0. I
haven't heard of any implementations that have an initial capacity other
than 0, but it would be legal.



flimfl...@gmail.com

unread,
Dec 16, 2015, 7:30:56 PM12/16/15
to
On Wednesday, December 16, 2015 at 5:00:03 PM UTC-7, David Brown wrote:

> Ask yourself /why/ you are adding x_ to the class. What is it doing?
> How does it affect the behaviour of the class? And in particular, how
> does it affect the class's invariant? If it has no effect on the
> invariant, it doesn't matter how it is initialised. But if it /does/
> have a part to play, as one would normally expect, then you need to
> initialise it correctly. Of course that means editing the constructor -
> adding the member to the class definition is only half the job.
>
> If the compiler always initialised it to 0, then you would /still/ have
> to look through the constructor, and think through the process - is 0 an
> appropriate initial value here? Having the compiler initialise it to 0
> saves you a negligible amount of time - it's a few seconds work to add
> the x_(0) to the constructor. Most of the time and effort is thinking
> about it - and you must do that anyway. Having the compiler make a
> default that is sometimes appropriate risks letting you get away with
> not thinking - and that's a bad thing.

There are times when the code is flying faster than this. Sometimes days are spent on the same 100 lines (i.e. designing a lock free interaction), and sometimes 1000 lines are written in a matter of hours highly iteratively (i.e. writing a boss battle for a hop & bop), and because of the nature of the two systems you could well have more faith in the latter. It's that second type of example where sometimes I get weary of declaration, initialization, and implementation all being in different places.


> > I do see these warnings a lot when the declaration, lack of
> > initialization, and usage are all together. I've never seen such a
> > warning when the data I forgot to initialize was a class member
> > variable. Is that even possible? I use msvc, clang, ghs, armcc,
> > codewarrior, and sn on a regular basis and I can't remember any analysis
> > picking up on this type of mistake with uninitialized members.
> >
>
> If you see these warnings a lot, your coding practice is bad. These
> warnings show that you are doing something wrong. There are good for
> catching the occasional typo or glip, but if you get them often you
> should think about how you are writing your code.

I don't mean I'm somehow endlessly vexed by them. I mean I'm quite familiar with them, because over the years I've seen them enough to appreciate their existence. I've made a lot of typos and glips over my life.


> The compiler won't be able to guess about initialisation across compile
> units (it might be able to do it with link-time optimisation). It can
> only hope to see the issue if you made your constructors inline along
> with the class definition.

Agreed. Again, this is the case that motivates me. While I appreciate static compiler analysis, this is why I don't feel satisfied by it.


> Putting 5 ints into std::vector<int> would be a reasonable default
> constructor - the main point is to make it consistent according to the
> class's invariant. But it turns out that initialising the vector to
> empty is the easiest and most efficient way to establish the invariant,
> and it is convenient for everyone. So it is specified this way in the
> standard - and we could complain if it didn't follow that standard.

I think I see your point. It's not just that the invariants are satisfied, but that they are satisfied most efficiently. That might be the key consistency link I've been searching for to rationalize the current state of things.


Sorry about messing up the attributions. I kept yours at the top of this email. I don't do newsgroup postings - ever - not sure what possessed me today!

Paavo Helde

unread,
Dec 17, 2015, 3:05:56 AM12/17/15
to
David Brown <david...@hesbynett.no> wrote in
news:n4stov$7oq$1...@dont-email.me:

> On 17/12/15 00:31, flimfl...@gmail.com wrote:
>> class Gizmo {
>> public:
>> Gizmo();
>> ... blah blah
>> private:
>> int x_; // I just added this member
>> };
>
> Ask yourself /why/ you are adding x_ to the class. What is it doing?
> Of course that means editing the constructor
> - adding the member to the class definition is only half the job.

It becomes worse if there is not one, but many constructors (C++11
forarding constructors would help here, BTW), plus the copy constructor,
assignment, move constructor, move assignment, swap function.

It is even worse when the new member needs to be initialized only in some
cases, depending on the other values. Just a couple of days ago I added a
new bool field to a low-level critical-speed variant-type class which had
ca 12 constructors, 4 of which required initialization of the new field.
Plus the copy/move ctor/assignment, plus swap. No fun, I can tell.

Cheers,
Paavo

David Brown

unread,
Dec 17, 2015, 7:14:28 AM12/17/15
to
(As Ian says, please don't snip attributions. Also try to get your line
wrapping in order. I see you are using the Google Groups interface,
which is the worst Usenet client around - you have to go to some effort
to follow standard Usenet conventions. If you are going to use Usenet,
I strongly recommend you get a proper newsreader and server. Unless you
have particular needs, a good and free combination is Thunderbird
newsreader with news.eternal-september.org as the server.)
That is no excuse. Write the code correctly, in the correct place. If
you are coding so fast that it is an effort to track initialisations,
you are coding too fast - it is much better to take the time needed to
write code correctly first, than to spend more time trying to debug it
later.

If it is more convenient for you, then you might consider changing your
style a little to put the initialisation in the class declaration rather
than the class implementation file - then you don't have to jump around
between two parts of the code. (Of course, a reasonable IDE will let
you have both files open at the same time - keeping them consistent
should not be difficult.)

>
>
>>> I do see these warnings a lot when the declaration, lack of
>>> initialization, and usage are all together. I've never seen such
>>> a warning when the data I forgot to initialize was a class
>>> member variable. Is that even possible? I use msvc, clang, ghs,
>>> armcc, codewarrior, and sn on a regular basis and I can't
>>> remember any analysis picking up on this type of mistake with
>>> uninitialized members.
>>>
>>
>> If you see these warnings a lot, your coding practice is bad.
>> These warnings show that you are doing something wrong. There are
>> good for catching the occasional typo or glip, but if you get them
>> often you should think about how you are writing your code.
>
> I don't mean I'm somehow endlessly vexed by them. I mean I'm quite
> familiar with them, because over the years I've seen them enough to
> appreciate their existence. I've made a lot of typos and glips over
> my life.
>
>
>> The compiler won't be able to guess about initialisation across
>> compile units (it might be able to do it with link-time
>> optimisation). It can only hope to see the issue if you made your
>> constructors inline along with the class definition.
>
> Agreed. Again, this is the case that motivates me. While I
> appreciate static compiler analysis, this is why I don't feel
> satisfied by it.

Static analysis is an aid to spotting mistakes - it is not an automatic
code reviewer.

>
>
>> Putting 5 ints into std::vector<int> would be a reasonable default
>> constructor - the main point is to make it consistent according to
>> the class's invariant. But it turns out that initialising the
>> vector to empty is the easiest and most efficient way to establish
>> the invariant, and it is convenient for everyone. So it is
>> specified this way in the standard - and we could complain if it
>> didn't follow that standard.
>
> I think I see your point. It's not just that the invariants are
> satisfied, but that they are satisfied most efficiently. That might
> be the key consistency link I've been searching for to rationalize
> the current state of things.

The key to initialising an object or variable is that it must be put in
a valid self-consistent state. If no specific value is given, then in
should be initialised in the most efficient way to establish consistency
- it is then up to the user of the object to put a useful value into it.

>
>
> Sorry about messing up the attributions. I kept yours at the top of
> this email. I don't do newsgroup postings - ever - not sure what
> possessed me today!
>

You kept my attribution, but snipped the others. As long as there are
quotations in the post, the attributions at the top should show where
they cam from - thus the attribution list should match the maximum depth
of the nested quotations. (It's okay if there are a few extra
attributions extra, or if there is a little mismatch on deeply quoted
messages - but the last few attributions at least should be correct.)

Bo Persson

unread,
Dec 17, 2015, 11:12:22 AM12/17/15
to
On 2015-12-16 20:59, flimfl...@gmail.com wrote:
> I've long wished C++ worked a bit like this:
>
> int x; // initialized to zero in all scopes (not just global)
>
> int y = std::undefined; // it's left uninitialized, only when I say so
>
> struct Foo {
> Foo() { }
> Foo(std::undefined_t) : x_(std::undefined) { }
> int x_;
> };
>
> struct Bar {
> Bar() { }
> int x_;
> };
>
>
> Foo foo; // foo.x_ is zero
> Foo foo = std::undefined; // foo.x_ is undefined
>
> Bar bar; // bar.x_ is zero
> Bar bar = std::undefined; // compiler error
>
> I know there's at least a few of us out there who would welcome this sort of thing. I also know there's massive opposition to this from really smart people, and so I want to learn from you. If I could understand why it's better for built-ins to be undefined by default rather than by request, it would be a great help to me.
>
> Please keep in mind I'm asking for guidance completely separate from the issues of legacy code or precedent set by C. I understand many of those issues. I instead want to learn why it shouldn't be done even if C++ were being designed for the first time today. If I could get that through my thick head, I'd be very happy.
>

But is HAS to do with C compatibility. And performance.

If C++ were to initialize all C compatible types, the internet would be
full of benchmarks showing how crappy C++ is and that C runs circles
around it:

void f()
{
int x[10000000];
}


"How come safe-C++ runs this simple function a million times slower than
a C program?"



Bo Persson



mark

unread,
Dec 17, 2015, 11:39:24 AM12/17/15
to
On 2015-12-17 00:59, David Brown wrote:

> If the compiler always initialised it to 0, then you would /still/ have
> to look through the constructor, and think through the process - is 0 an
> appropriate initial value here? Having the compiler initialise it to 0
> saves you a negligible amount of time - it's a few seconds work to add
> the x_(0) to the constructor. Most of the time and effort is thinking
> about it - and you must do that anyway. Having the compiler make a
> default that is sometimes appropriate risks letting you get away with
> not thinking - and that's a bad thing.

I strongly disagree with you. 95% of the time, 0-initialization would be
a sane thing to do. If you have several constructors, it's way too easy
to forget one (at least with C++11, you now have delegating constructors
and in-class member initializers).

What's worse, things may work fine depending on compile / optimization
settings, where you end up with 0-initialized memory, so this is easy
for tests to miss.

Undiagnosed non-deterministic behavior is really, really bad.

flimfl...@gmail.com

unread,
Dec 17, 2015, 1:05:45 PM12/17/15
to
On Thursday, December 17, 2015 at 5:14:28 AM UTC-7, David Brown wrote:
> That is no excuse. Write the code correctly, in the correct place. If
> you are coding so fast that it is an effort to track initialisations,
> you are coding too fast - it is much better to take the time needed to
> write code correctly first, than to spend more time trying to debug it
> later.

It's not an excuse, it's a reality of a certain subset of code that I write. The problem spaces that you and I work in apparently don't intersect here. "Tracking" initialization is not the problem.

C++11 does indeed allow me to initialize at the point of declaration for members, which would help the convenience issue in those fast/high-volume coding situations. In my case though, I'm still handcuffed to C++03 for reasons outside my control.

It really helps a lot to have a consistent rationale for why int and vector<int> are not so different in how they default construct - Thankyou! I've definitely learned something valuable with this thread. Still though, I feel there's a subset of code that I write where knowing that int's invariants are satisfied at construction is not as good as knowing that it has either a predictable value or an explicitly requested unspecified value.

I'm think I'm realizing that my long-held approach of using pure C++ for all levels of application development needs to budge. I've really been a stick in the mud on this, but I'm inspired now to try mixing in D or Rust for certain parts of my applications where those languages might fit better.

flimfl...@gmail.com

unread,
Dec 17, 2015, 1:09:21 PM12/17/15
to
int x[10000000] = { void }; // would be just as fast
}

asetof...@gmail.com

unread,
Dec 17, 2015, 1:26:16 PM12/17/15
to
int x[10000000] = { 0 };

David Brown

unread,
Dec 17, 2015, 4:27:27 PM12/17/15
to
On 17/12/15 19:05, flimfl...@gmail.com wrote:
> On Thursday, December 17, 2015 at 5:14:28 AM UTC-7, David Brown
> wrote:
>> That is no excuse. Write the code correctly, in the correct place.
>> If you are coding so fast that it is an effort to track
>> initialisations, you are coding too fast - it is much better to
>> take the time needed to write code correctly first, than to spend
>> more time trying to debug it later.
>
> It's not an excuse, it's a reality of a certain subset of code that I
> write. The problem spaces that you and I work in apparently don't
> intersect here. "Tracking" initialization is not the problem.
>
> C++11 does indeed allow me to initialize at the point of declaration
> for members, which would help the convenience issue in those
> fast/high-volume coding situations. In my case though, I'm still
> handcuffed to C++03 for reasons outside my control.

If you have the freedom to consider D or Rust, then surely you also have
the freedom to move to C++11? C++11 is a significantly better language
than C++03 in many ways, and is worth pushing for.

>
> It really helps a lot to have a consistent rationale for why int and
> vector<int> are not so different in how they default construct -
> Thankyou! I've definitely learned something valuable with this
> thread. Still though, I feel there's a subset of code that I write
> where knowing that int's invariants are satisfied at construction is
> not as good as knowing that it has either a predictable value or an
> explicitly requested unspecified value.

It really isn't hard to write "int x = 0;" in the few occasions where
you have a local int variable that you don't want to initialise to a
particular value, yet want to initialise to /something/. I realise it
looks somewhat inconsistent, but C++ has always had a distinction
between "plain" data types and object types.

>
> I'm think I'm realizing that my long-held approach of using pure C++
> for all levels of application development needs to budge. I've
> really been a stick in the mud on this, but I'm inspired now to try
> mixing in D or Rust for certain parts of my applications where those
> languages might fit better.
>

To my mind, there is not much difference between C++ and D and Rust -
they cover a similar application arena. There are certainly types of
application where C++ is not the most efficient development language -
but changing to something very different, such as Python, is likely to
have much more impact.

David Brown

unread,
Dec 17, 2015, 4:35:15 PM12/17/15
to
Automatic zero initialisation of "int" (and other PODs) does two things.
One is that it gives you a specific known value, that may or may not
be of any use. Two is that it removes any chance the compiler has of
telling you that you haven't actually initialised it to anything useful.

So my recommendation is to initialise your variables in the correct way
for the code - don't put in dummy initialisations that disable helpful
warnings, and perhaps mislead the reader.


flimfl...@gmail.com

unread,
Dec 17, 2015, 5:29:52 PM12/17/15
to
On Thursday, December 17, 2015 at 2:27:27 PM UTC-7, David Brown wrote:
> On 17/12/15 19:05, flimfl...@gmail.com wrote:
> > On Thursday, December 17, 2015 at 5:14:28 AM UTC-7, David Brown
> > wrote:
> >> That is no excuse. Write the code correctly, in the correct place.
> >> If you are coding so fast that it is an effort to track
> >> initialisations, you are coding too fast - it is much better to
> >> take the time needed to write code correctly first, than to spend
> >> more time trying to debug it later.
> >
> > It's not an excuse, it's a reality of a certain subset of code that I
> > write. The problem spaces that you and I work in apparently don't
> > intersect here. "Tracking" initialization is not the problem.
> >
> > C++11 does indeed allow me to initialize at the point of declaration
> > for members, which would help the convenience issue in those
> > fast/high-volume coding situations. In my case though, I'm still
> > handcuffed to C++03 for reasons outside my control.
>
> If you have the freedom to consider D or Rust, then surely you also have
> the freedom to move to C++11? C++11 is a significantly better language
> than C++03 in many ways, and is worth pushing for.
>

I use C++11 everywhere I can. It's a great improvement to say the least. The reason I'm handcuffed to C++03 has to do with hardware vendor tools/libraries (a certain game console manufacturer providing only C++03 tools with no plans to ever move to C++11 so for current gen hardware, and who provides required SDKs compiled in said C++03 environment, exposed as C++ interfaces - not C, which sorta locks you into using the same compiler they do).

My thinking was:
1) A layer of Rust or D application code on top which consumes / calls into...
2) A thin C interface to our libraries (so the ABI is manageable) which wraps...
3) Our C++ library components (written in 11 or 03, whatever hw vendor provides) which calls into...
4) Required hardware vendor SDKs sometimes exposed as C++03 interfaces.

I suppose I could stick clang C++11 at #1 just as well as Rust or D - but sure doesn't feel right. If was going to go that far, I'd rather see what Rust and D had to offer up there - at least I'd know that when coding in layer #1 I'd have known default values for int/bool/etc - which is the only place I've found myself wanting that behavior.

Besides, there are other things about C++ that I find not very ergonomic when writing certain subsets of code. I didn't want to turn this into a C++ rant - I love the language dearly. I guess I was hoping D and/or Rust might help with those areas too (no idea - almost completely ignorant of their features).

> >
> > It really helps a lot to have a consistent rationale for why int and
> > vector<int> are not so different in how they default construct -
> > Thankyou! I've definitely learned something valuable with this
> > thread. Still though, I feel there's a subset of code that I write
> > where knowing that int's invariants are satisfied at construction is
> > not as good as knowing that it has either a predictable value or an
> > explicitly requested unspecified value.
>
> It really isn't hard to write "int x = 0;" in the few occasions where
> you have a local int variable that you don't want to initialise to a
> particular value, yet want to initialise to /something/. I realise it
> looks somewhat inconsistent, but C++ has always had a distinction
> between "plain" data types and object types.

int x = 0 isn't what I want to avoid. I want to avoid:

class Foo {
Foo();
int x_;
}

... and then somewhere else, perhaps a different file altogether:

Foo::Foo() : x_(0) { }

Which does come back to C++11 again.

>
> >
> > I'm think I'm realizing that my long-held approach of using pure C++
> > for all levels of application development needs to budge. I've
> > really been a stick in the mud on this, but I'm inspired now to try
> > mixing in D or Rust for certain parts of my applications where those
> > languages might fit better.
> >
>
> To my mind, there is not much difference between C++ and D and Rust -
> they cover a similar application arena. There are certainly types of
> application where C++ is not the most efficient development language -
> but changing to something very different, such as Python, is likely to
> have much more impact.

You may be right.


GOD I hope I got the annotations right this time!!!!!!

David Brown

unread,
Dec 18, 2015, 3:11:05 AM12/18/15
to
> but sure doesn't feel right. If was going to go that far, I'd rather see
> what Rust and D had to offer up there - at least I'd know that when
> coding in layer #1 I'd have known default values for int/bool/etc -
> which is the only place I've found myself wanting that behavior.

It is still going to be much easier to mix some C++11 with the C++03
stuff than to bring in D or Rust. The chances are high that the C++03
stuff will compile fine with C+11 standards, but you might have to be
careful with api settings to make the linking match up (gcc at least
gives you control of that from command-line switches - I don't know what
compiler you are actually using here).

>
> Besides, there are other things about C++ that I find not very
> ergonomic when writing certain subsets of code. I didn't want to turn
> this into a C++ rant - I love the language dearly. I guess I was hoping
> D and/or Rust might help with those areas too (no idea - almost
> completely ignorant of their features).
>

By all means, investigate D and Rust. Even if you don't use them in the
end, you could get new ideas or inspiration to bring back to your C++
programming. Just don't expect wonders here - you might find a few nice
points in these languages compared to C++, but you will also lose a lot
- and I doubt if the balance is worth the effort of mixing the
languages. (It is a another matter if you go for Python or something
seriously different, where there are some things that are /much/ easier.)

>>>
>>> It really helps a lot to have a consistent rationale for why int and
>>> vector<int> are not so different in how they default construct -
>>> Thankyou! I've definitely learned something valuable with this
>>> thread. Still though, I feel there's a subset of code that I write
>>> where knowing that int's invariants are satisfied at construction is
>>> not as good as knowing that it has either a predictable value or an
>>> explicitly requested unspecified value.
>>
>> It really isn't hard to write "int x = 0;" in the few occasions where
>> you have a local int variable that you don't want to initialise to a
>> particular value, yet want to initialise to /something/. I realise it
>> looks somewhat inconsistent, but C++ has always had a distinction
>> between "plain" data types and object types.
>
> int x = 0 isn't what I want to avoid. I want to avoid:
>
> class Foo {
> Foo();
> int x_;
> }
>
> ... and then somewhere else, perhaps a different file altogether:
>
> Foo::Foo() : x_(0) { }
>
> Which does come back to C++11 again.
>

It's very simple. Either it doesn't matter that x_ is not initialised
(and for many members, that is the case), or you initialise it in the
class's constructor. That is what the constructor is for!

>>
>>>
>>> I'm think I'm realizing that my long-held approach of using pure C++
>>> for all levels of application development needs to budge. I've
>>> really been a stick in the mud on this, but I'm inspired now to try
>>> mixing in D or Rust for certain parts of my applications where those
>>> languages might fit better.
>>>
>>
>> To my mind, there is not much difference between C++ and D and Rust -
>> they cover a similar application arena. There are certainly types of
>> application where C++ is not the most efficient development language -
>> but changing to something very different, such as Python, is likely to
>> have much more impact.
>
> You may be right.
>
>
> GOD I hope I got the annotations right this time!!!!!!
>

Yes, the /attributions/ were absolutely fine - thanks.

(You still haven't fixed your wrapping problem. It is quick enough for
others with proper newsclients to re-wrap some posts, but it's a pain
when you have formatted text such as code or lists. Again, I know this
is a problem when using google groups. If you switch to a proper
newsclient, you'll find Usenet far easier to use. GG is fine for
searching across a range of groups, but for regular use a newsreader is
much more efficient and convenient.)

flimfl...@gmail.com

unread,
Dec 18, 2015, 1:19:13 PM12/18/15
to
C++ from one compiler vendor cannot link against C++ from another compiler vendor, irrespective of whether either or both are 11 or 03. Name mangling won't match at the very least, among other issues. I can't build C++ (with say gcc) on top of C++ built with ghs for instance (one of the specific compilers I can't opt out of). A C layer would have to be in between them for the standard ABI.

I'd feel a bit silly having C++ on C on C++. It would get me some C++11 features for some of the code, but I'd feel less silly if I was doing that for Rust or D or something else entirely. Rust on C on C++ looks less nuts somehow.

Also, C++11 allowing me to write member x_ = 0 in my class declarations gets me close, but not 100% to where I'd rather be with respect to member variables. Again, this applies only to particular subsets of my code, where it's tangibly better for me if all objects default construct to the most likely desired initial state (like vector<int> does), rather than the fastest establishment of invariants (like both int and vector<int> do as you pointed out). I don't know much about D or Rust yet, but I do know they both do this.

I naively thought "hey, allowing x = std::unspecified" (or x = void like D) would be having the cake and eating it too, but I accept the wisdom of others that this would do more harm than good. Many in my particular industry have long abandoned pure C++, opting for a mix of C++ and something else (often lua or C#) I'm slowly & stubbornly realizing that perhaps they're not all just crazy kids.
That's not my issue either. I am neither unwilling to write local "int x = 0", nor am I unsure where I am required to initialize member x_. For member x_, the few seconds it takes to initialize in the required location is an insignficant non-issue much of the code I write, but a tangible source of minor drag in other code I write. I don't want to break the language to satisfy my desires in those specific contexts, and I accept that the suggestion of "int x is zero unless stated unspecified" would do just that.

I think I just need a highly iterative language to sit on top of my highly optimized language. Might not be D or Rust. I've done nothing other than C++/C/ASM for my entire career, so other languages are very new ground for me.

Öö Tiib

unread,
Dec 19, 2015, 12:13:07 AM12/19/15
to
Yes, or some other layer (like SWIG). IOW C++ ABI isn't standardized but
may be one day.

>
> I'd feel a bit silly having C++ on C on C++. It would get me some
> C++11 features for some of the code, but I'd feel less silly if I was
> doing that for Rust or D or something else entirely. Rust on C on C++
> looks less nuts somehow.

All the differences between common programming languages are irrelevant
syntax sugar. What is the difference if I have to write "int x = void;"
or "int_fast16_t x;" to get uninitialized integer variable named "x"?
I fail to see major benefits of neither syntax. Just type what is needed
and done.

>
> Also, C++11 allowing me to write member x_ = 0 in my class declarations
> gets me close, but not 100% to where I'd rather be with respect to
> member variables.

It is actually unclear where you want to be with data members of your
classes. The 'struct' of C is mostly fine. C++ added some convenience;
C++11 added even more convenience. It feels that I can type and read
too fast ... so the convenience does give next to no returns. IDEs
that try to be overly helpful and convenient on top of that (like Apple
Xcode) are becoming outright annoying with that help.

> Again, this applies only to particular subsets of my code, where
> it's tangibly better for me if all objects default construct to the
> most likely desired initial state (like vector<int> does), rather than
> the fastest establishment of invariants (like both int and vector<int>
> do as you pointed out). I don't know much about D or Rust yet, but I
> do know they both do this.

Is it really so hard to type "int_fast16_t x = INT_MIN;" if you need that
"x" to be initialized? To me the issues of software development are
always totally elsewhere.

>
> I naively thought "hey, allowing x = std::unspecified" (or x = void like
> D) would be having the cake and eating it too, but I accept the wisdom
> of others that this would do more harm than good. Many in my
> particular industry have long abandoned pure C++, opting for a mix of C++
> and something else (often lua or C#) I'm slowly & stubbornly realizing
> that perhaps they're not all just crazy kids.

The programming languages are software design tools. There's no
point whatsoever to change C++ to be exactly like some other programming
language. People who like C# or lua should use those instead of C++.
In C++ you are not required to initialize anything.

> For member x_, the few seconds it takes to initialize in the
> required location is an insignficant non-issue much of the code I
> write, but a tangible source of minor drag in other code I write. I
> don't want to break the language to satisfy my desires in those
> specific contexts, and I accept that the suggestion of "int x is zero
> unless stated unspecified" would do just that.

In C++ int is zero when it is stated to be zero.

>
> I think I just need a highly iterative language to sit on top of my
> highly optimized language. Might not be D or Rust. I've done
> nothing other than C++/C/ASM for my entire career, so other languages
> are very new ground for me.

If you need some sort of language to sit somewhere then put it to sit
there.


mark

unread,
Dec 19, 2015, 3:29:34 AM12/19/15
to
On 2015-12-19 06:12, Öö Tiib wrote:
> Is it really so hard to type "int_fast16_t x = INT_MIN;" if you need that
> "x" to be initialized?

I find it extremely funny that you post a buggy initialization snippet,
especially in the context of this discussion.

No, it's not hard to type. But programmers make mistakes. It's very easy
to forget an initialization somewhere and the infrastructure for
tracking that down is far from perfect. Security bugs from using
uninitialized variables are quite common.

Öö Tiib

unread,
Dec 19, 2015, 10:40:19 AM12/19/15
to
On Saturday, 19 December 2015 10:29:34 UTC+2, mark wrote:
> On 2015-12-19 06:12, Öö Tiib wrote:
> > Is it really so hard to type "int_fast16_t x = INT_MIN;" if you need that
> > "x" to be initialized?
>
> I find it extremely funny that you post a buggy initialization snippet,
> especially in the context of this discussion.

I would find it funny as well but can you point out what defect you did
mean? I was really afraid that the damn auto-almost-thinking-for-me IDEs
have already made me to forget the syntax. :D

Code:

#include <iostream>
#include <stdint.h>
#include <limits.h>

int main()
{
int_fast16_t x = INT_MIN;
std::cout << x << "\r";
}

Output:

-2147483648

Was it to demonstrate how the reviewers do mistakes as well?

>
> No, it's not hard to type. But programmers make mistakes. It's very easy
> to forget an initialization somewhere and the infrastructure for
> tracking that down is far from perfect. Security bugs from using
> uninitialized variables are quite common.

I fully agree with all those points. Debug tools are better or worse but
none is perfect and some defects are harder to track down than others but
none is avoidable. Programmer is still most major factor of success but
produces defects rapidly on all levels.

However how is it relevant? Most buggy program and uselessly non-maintainable
code that I have ever seen was written in C#. The syntax sugar and quality
of tools are matter of taste and tiny difference in convenience. My own
feeling is that the almost too convenient tools try to write almost
everything in that almost too convenient syntax for me. :D USENET is good,
here I can at least type something myself.

mark

unread,
Dec 19, 2015, 12:14:13 PM12/19/15
to
On 2015-12-19 16:39, Öö Tiib wrote:
>> >
>> >I find it extremely funny that you post a buggy initialization snippet,
>> >especially in the context of this discussion.
> I would find it funny as well but can you point out what defect you did
> mean? I was really afraid that the damn auto-almost-thinking-for-me IDEs
> have already made me to forget the syntax. :D
>
> Code:
>
> #include <iostream>
> #include <stdint.h>
> #include <limits.h>
>
> int main()
> {
> int_fast16_t x = INT_MIN;
> std::cout << x << "\r";
> }
>
> Output:
>
> -2147483648

int_fast16_t might be 16 bits only (and int 16-bit ones' complement or
32 bits) - so you have an integer overflow. One of the nasty kind, with
undefined behavior.

You would probably be saved by a compiler warning, someone else using
your code might not look at them.

I don't even have to do dig up some obscure platform. Chromium stdint.h
for Visual C++ (int is int32_t):

// 7.18.1.3 Fastest minimum-width integer types
typedef int8_t int_fast8_t;
typedef int16_t int_fast16_t;
typedef int32_t int_fast32_t;
typedef int64_t int_fast64_t;
typedef uint8_t uint_fast8_t;
typedef uint16_t uint_fast16_t;
typedef uint32_t uint_fast32_t;
typedef uint64_t uint_fast64_t;

Öö Tiib

unread,
Dec 19, 2015, 1:59:23 PM12/19/15
to
On Saturday, 19 December 2015 19:14:13 UTC+2, mark wrote:
> On 2015-12-19 16:39, Öö Tiib wrote:
> >> >
> >> >I find it extremely funny that you post a buggy initialization snippet,
> >> >especially in the context of this discussion.
> > I would find it funny as well but can you point out what defect you did
> > mean? I was really afraid that the damn auto-almost-thinking-for-me IDEs
> > have already made me to forget the syntax. :D
> >
> > Code:
> >
> > #include <iostream>
> > #include <stdint.h>
> > #include <limits.h>
> >
> > int main()
> > {
> > int_fast16_t x = INT_MIN;
> > std::cout << x << "\r";
> > }
> >
> > Output:
> >
> > -2147483648
>
> int_fast16_t might be 16 bits only (and int 16-bit ones' complement or
> 32 bits) - so you have an integer overflow. One of the nasty kind, with
> undefined behavior.

'int_fast16_t' is guaranteed to be the fastest integral type with a size of
at least 16 bits. 'int' is guaranteed to be the fastest integral type with
a range of at least [-32767,32767]. Now explain, how it can't be that 'int_fast16_t' can not represent all values of 'int' including 'INT_MIN'.

> You would probably be saved by a compiler warning, someone else using
> your code might not look at them.

Warning about what? There was no defect at first place.

>
> I don't even have to do dig up some obscure platform. Chromium stdint.h
> for Visual C++ (int is int32_t):
>
> // 7.18.1.3 Fastest minimum-width integer types
> typedef int8_t int_fast8_t;
> typedef int16_t int_fast16_t;
> typedef int32_t int_fast32_t;
> typedef int64_t int_fast64_t;
> typedef uint8_t uint_fast8_t;
> typedef uint16_t uint_fast16_t;
> typedef uint32_t uint_fast32_t;
> typedef uint64_t uint_fast64_t;

What C++ compiler/platform is Chromium? AFAIK it is a web browser.
Seems it contains stdint.h indeed but I can't observe the code that
you describe:

https://chromium.googlesource.com/chromiumos/third_party/coreboot/+/5ef93446471589941c7bedc84bdd49a0ae3e2bbb/src/arch/x86/include/stdint.h

Quote:

typedef signed int int_fast16_t;

Perhaps post from where you took your odd code. Internet is indeed full
of buggy implementations of any standard function, class, macro or even
typedef but I do not use such.

David Brown

unread,
Dec 19, 2015, 2:15:07 PM12/19/15
to
On 19/12/15 19:58, 嘱 Tiib wrote:
> On Saturday, 19 December 2015 19:14:13 UTC+2, mark wrote:
>> On 2015-12-19 16:39, 嘱 Tiib wrote:
>>>>>
>>>>> I find it extremely funny that you post a buggy
>>>>> initialization snippet, especially in the context of this
>>>>> discussion.
>>> I would find it funny as well but can you point out what defect
>>> you did mean? I was really afraid that the damn
>>> auto-almost-thinking-for-me IDEs have already made me to forget
>>> the syntax. :D
>>>
>>> Code:
>>>
>>> #include <iostream> #include <stdint.h> #include <limits.h>
>>>
>>> int main() { int_fast16_t x = INT_MIN; std::cout << x << "\r"; }
>>>
>>> Output:
>>>
>>> -2147483648
>>
>> int_fast16_t might be 16 bits only (and int 16-bit ones' complement
>> or 32 bits) - so you have an integer overflow. One of the nasty
>> kind, with undefined behavior.
>
> 'int_fast16_t' is guaranteed to be the fastest integral type with a
> size of at least 16 bits. 'int' is guaranteed to be the fastest
> integral type with a range of at least [-32767,32767]. Now explain,
> how it can't be that 'int_fast16_t' can not represent all values of
> 'int' including 'INT_MIN'.
>

Not quite - "int" is guaranteed to be the most /natural/ integer type
(with a range of at least -32767..32767) of a given platform, not
necessarily the fastest. And "fastest" might vary according to details
of the chip and system. For example, on the 68332 microcontroller,
"int" is 32-bit because it is the standard for that ISA (m68k) and the
natural size for the cpu, its ALU and its registers. However, the chip
has only a 16-bit bus - 16-bit values are measurably faster when storing
data in off-chip memory, and therefore a sensible choice for
"int_fast16_t" would be 16-bit. On other platforms, the compiler
implementer might have decided that the more efficient use of cache
means that 16-bit values are faster than 32-bit values, and implemented
int_fast16_t as a 16-bit short int.

(It is also quite possible to use C++ on a cpu in which normal "int" is
not two's complement, while int_fast16_t must be two's complement - but
that's getting rather hypothetical.)

However, my main objection to "int_fast16_t x = INT_MIN;" is in how it
reads - the code says you want x to have at least 16 bits, be as fast as
possible, and you don't care about anything more than 16 bits. By
coincidence to the way C++ is implemented on your system, the code works
- but it is a poor way of writing it.

Öö Tiib

unread,
Dec 19, 2015, 3:59:32 PM12/19/15
to
Are there C++ compilers with 'int_fast16_t' of 16 bits and 'int'
32 bits? Ok, maybe asking for C++ is too much ... are there such C99
implementations?

>
> (It is also quite possible to use C++ on a cpu in which normal "int" is
> not two's complement, while int_fast16_t must be two's complement - but
> that's getting rather hypothetical.)
>
> However, my main objection to "int_fast16_t x = INT_MIN;" is in how it
> reads - the code says you want x to have at least 16 bits, be as fast as
> possible, and you don't care about anything more than 16 bits. By
> coincidence to the way C++ is implemented on your system, the code works
> - but it is a poor way of writing it.

OK. That is good objection on its own. Ont the other hand typing
"int_fast16_t x = std::numeric_limits<int_fast16_t>::min();" is sort of
at ugly side.

Unsure what to do then. I usually leave variables about whose value I
am uncertain at declaration point uninitialized. If there was really
some requirement to have everything initialized then I would like to
have the most useless and unlikely value so code attempting to use it
will most likely blow up. Signed minimum feels like perfect for that.

mark

unread,
Dec 19, 2015, 4:15:56 PM12/19/15
to
On 2015-12-19 19:58, Öö Tiib wrote:
> On Saturday, 19 December 2015 19:14:13 UTC+2, mark wrote:
>> On 2015-12-19 16:39, Öö Tiib wrote:
>>>>>
>>>>> I find it extremely funny that you post a buggy initialization snippet,
>>>>> especially in the context of this discussion.
>>> I would find it funny as well but can you point out what defect you did
>>> mean? I was really afraid that the damn auto-almost-thinking-for-me IDEs
>>> have already made me to forget the syntax. :D
>>>
>>> Code:
>>>
>>> #include <iostream>
>>> #include <stdint.h>
>>> #include <limits.h>
>>>
>>> int main()
>>> {
>>> int_fast16_t x = INT_MIN;
>>> std::cout << x << "\r";
>>> }
>>>
>>> Output:
>>>
>>> -2147483648
>>
>> int_fast16_t might be 16 bits only (and int 16-bit ones' complement or
>> 32 bits) - so you have an integer overflow. One of the nasty kind, with
>> undefined behavior.
>
> 'int_fast16_t' is guaranteed to be the fastest integral type with a size of
> at least 16 bits. 'int' is guaranteed to be the fastest integral type with
> a range of at least [-32767,32767]. Now explain, how it can't be that 'int_fast16_t' can not represent all values of 'int' including 'INT_MIN'.

Yes. But 'int' can just as well be 32 bits with INT_MIN=–2147483648. A
16-bit 'int_fast16_t' can't represent that.

>> You would probably be saved by a compiler warning, someone else using
>> your code might not look at them.
>
> Warning about what? There was no defect at first place.

Warning about your BUG.

#include <iostream>
#include <stdint.h>
#include <limits.h>

int main() {
int_fast16_t x = INT_MIN;
std::cout << sizeof(x) << " " << x << "\n";
std::cout << sizeof(int_fast16_t) << " " << sizeof(INT_MIN) << "\n";
}


$ g++ --version
g++.exe (Rev4, Built by MSYS2 project) 5.2.0

$ g++ int_fast16_t.cpp -o int_fast16_t.exe
int_fast16_t.cpp: In function 'int main()':
int_fast16_t.cpp:6:22: warning: overflow in implicit constant conversion
[-Woverflow]
int_fast16_t x = INT_MIN;
^

$ ./int_fast16_t.exe
2 0
2 4


Öö Tiib

unread,
Dec 19, 2015, 4:33:00 PM12/19/15
to
On Saturday, 19 December 2015 23:15:56 UTC+2, mark wrote:
> On 2015-12-19 19:58, Öö Tiib wrote:
> > On Saturday, 19 December 2015 19:14:13 UTC+2, mark wrote:
> >> On 2015-12-19 16:39, Öö Tiib wrote:
> >>>>>
> >>>>> I find it extremely funny that you post a buggy initialization snippet,
> >>>>> especially in the context of this discussion.
> >>> I would find it funny as well but can you point out what defect you did
> >>> mean? I was really afraid that the damn auto-almost-thinking-for-me IDEs
> >>> have already made me to forget the syntax. :D
> >>>
> >>> Code:
> >>>
> >>> #include <iostream>
> >>> #include <stdint.h>
> >>> #include <limits.h>
> >>>
> >>> int main()
> >>> {
> >>> int_fast16_t x = INT_MIN;
> >>> std::cout << x << "\r";
> >>> }
> >>>
> >>> Output:
> >>>
> >>> -2147483648
> >>
> >> int_fast16_t might be 16 bits only (and int 16-bit ones' complement or
> >> 32 bits) - so you have an integer overflow. One of the nasty kind, with
> >> undefined behavior.
> >
> > 'int_fast16_t' is guaranteed to be the fastest integral type with a size of
> > at least 16 bits. 'int' is guaranteed to be the fastest integral type with
> > a range of at least [-32767,32767]. Now explain, how it can't be that 'int_fast16_t' can not represent all values of 'int' including 'INT_MIN'.
>
> Yes. But 'int' can just as well be 32 bits with INT_MIN=-2147483648. A
> 16-bit 'int_fast16_t' can't represent that.
>
> >> You would probably be saved by a compiler warning, someone else using
> >> your code might not look at them.
> >
> > Warning about what? There was no defect at first place.
>
> Warning about your BUG.
>
> #include <iostream>
> #include <stdint.h>
> #include <limits.h>
>
> int main() {
> int_fast16_t x = INT_MIN;
> std::cout << sizeof(x) << " " << x << "\n";
> std::cout << sizeof(int_fast16_t) << " " << sizeof(INT_MIN) << "\n";
> }
>
>
> $ g++ --version
> g++.exe (Rev4, Built by MSYS2 project) 5.2.0
>
> $ g++ int_fast16_t.cpp -o int_fast16_t.exe
> int_fast16_t.cpp: In function 'int main()':
> int_fast16_t.cpp:6:22: warning: overflow in implicit constant conversion
> [-Woverflow]
> int_fast16_t x = INT_MIN;
> ^
>
> $ ./int_fast16_t.exe
> 2 0
> 2 4

Ok, thanks, mea culpa.

Öö Tiib

unread,
Dec 19, 2015, 4:39:15 PM12/19/15
to
On Saturday, 19 December 2015 22:59:32 UTC+2, Öö Tiib wrote:
> On Saturday, 19 December 2015 21:15:07 UTC+2, David Brown wrote:
Nah, discard that. Seems that there is 'INT_FAST16_MIN' macro available.

David Brown

unread,
Dec 19, 2015, 5:06:13 PM12/19/15
to
I don't know of any off-hand, but I can't say I have had much use of
int_fast16_t on any of the tools I use. Usually I prefer the simpler
and more explicit int16_t form (or just "int" if appropriate).

>
>>
>> (It is also quite possible to use C++ on a cpu in which normal "int" is
>> not two's complement, while int_fast16_t must be two's complement - but
>> that's getting rather hypothetical.)
>>
>> However, my main objection to "int_fast16_t x = INT_MIN;" is in how it
>> reads - the code says you want x to have at least 16 bits, be as fast as
>> possible, and you don't care about anything more than 16 bits. By
>> coincidence to the way C++ is implemented on your system, the code works
>> - but it is a poor way of writing it.
>
> OK. That is good objection on its own. Ont the other hand typing
> "int_fast16_t x = std::numeric_limits<int_fast16_t>::min();" is sort of
> at ugly side.

Yes, but "int x = 0;" is pretty easy to type, and usually a better
choice of initialiser than INT_MIN.

>
> Unsure what to do then. I usually leave variables about whose value I
> am uncertain at declaration point uninitialized. If there was really
> some requirement to have everything initialized then I would like to
> have the most useless and unlikely value so code attempting to use it
> will most likely blow up. Signed minimum feels like perfect for that.
>

I can understand that. However, leaving them uninitialised and using
good warnings (if your compiler supports them) will mean that your code
"blows up" during compilation rather than when running, and that's the
best you can get.


Öö Tiib

unread,
Dec 19, 2015, 6:33:41 PM12/19/15
to
On Sunday, 20 December 2015 00:06:13 UTC+2, David Brown wrote:
> On 19/12/15 21:58, Öö Tiib wrote:
> > On Saturday, 19 December 2015 21:15:07 UTC+2, David Brown wrote:
> >> However, my main objection to "int_fast16_t x = INT_MIN;" is in how it
> >> reads - the code says you want x to have at least 16 bits, be as fast as
> >> possible, and you don't care about anything more than 16 bits. By
> >> coincidence to the way C++ is implemented on your system, the code works
> >> - but it is a poor way of writing it.
> >
> > OK. That is good objection on its own. Ont the other hand typing
> > "int_fast16_t x = std::numeric_limits<int_fast16_t>::min();" is sort of
> > at ugly side.
>
> Yes, but "int x = 0;" is pretty easy to type, and usually a better
> choice of initialiser than INT_MIN.

0 is most often needed but that makes it is also most incorrect when it
is yet unclear what is needed.

>
> >
> > Unsure what to do then. I usually leave variables about whose value I
> > am uncertain at declaration point uninitialized. If there was really
> > some requirement to have everything initialized then I would like to
> > have the most useless and unlikely value so code attempting to use it
> > will most likely blow up. Signed minimum feels like perfect for that.
> >
>
> I can understand that. However, leaving them uninitialised and using
> good warnings (if your compiler supports them) will mean that your code
> "blows up" during compilation rather than when running, and that's the
> best you can get.

That is what I usually do. Sometimes compiler does not catch a defect,
for example when uninitialized variable is passed by reference. Then I
can use valgrind and/or clangs -fsanitize=memory that blow it up run-time
and everything is still good. However I see that lot of people do not like
undetermined state.

Therefore I was trying to imagine of odd case when I do not know correct
value but for whatever odd requirement I may not leave it uninitialized
either. Perhaps it is then best to enwrap it into a class (that keeps
track of its value being determined) or to use something like
'boost::optional' on all such cases that I can imagine.

Jorgen Grahn

unread,
Dec 20, 2015, 12:51:33 PM12/20/15
to
On Wed, 2015-12-16, David Brown wrote:
> On 17/12/15 00:31, flimfl...@gmail.com wrote:
...
>> Those cases have never bothered me. What makes me want different behavior in C++ is this:
>>
>> In Gizmo.h:
>>
>> class Gizmo {
>> public:
>> Gizmo();
>> ... blah blah
>> private:
>> int x_; // I just added this member
>> };
>>
>> In Gizmo.cpp:
>>
>> Gizmo::Gizmo() :
>> x_(0) // and I have to go far away and do this too
>> {
>> }
>>
>
>> and I still haven't done anything with x_ yet, which happens in other
>> code that is similarly not next to declaration or initialization. C++11
>> allows me to do "int x_ = 0;" in the class declaration, but I can still
>> forget, and it's still a different requirement on me than if x_ had been
>> an std::vector<int>, or had static storage.
>
> Ask yourself /why/ you are adding x_ to the class. What is it doing?
> How does it affect the behaviour of the class? And in particular, how
> does it affect the class's invariant? If it has no effect on the
> invariant, it doesn't matter how it is initialised. But if it /does/
> have a part to play, as one would normally expect, then you need to
> initialise it correctly. Of course that means editing the constructor -
> adding the member to the class definition is only half the job.

Sometimes if you have problems with this, it means you're using too
primitive types. I once had a bunch of classes which kept statistics
counters for their work, up to a dozen or so each. The right thing to
do there was to create a counter<T> class and use it instead of
unsigned, unsigned long etc.

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Chris Vine

unread,
Dec 20, 2015, 2:59:14 PM12/20/15
to
On Sat, 19 Dec 2015 13:39:03 -0800 (PST)
Öö Tiib <oot...@hot.ee> wrote:
[snip]
> Nah, discard that. Seems that there is 'INT_FAST16_MIN' macro
> available.

In addition C++11 requires a a specialization of
std::numeric_limits<T>::min() for all arithmetic types (§3.9.1/8 and
§18.3.2.1/2). int_fast16_t is required to be a typedef to a signed
integer type, which is an arithmetic type.

Chris

flimfl...@gmail.com

unread,
Dec 22, 2015, 12:52:48 PM12/22/15
to
I accept that it's unclear to you. C++ is used in so many contexts, I really can't everyone else to get where I'm coming from. Some will, some won't.

Not sure how it relates, but 100% agreed on the "help" from tools. I fell in love with MSVS back in the late 90s, in part because of some of that help, but since then it's packed on so much crap I can hardly move around in it freely anymore.

>
> > Again, this applies only to particular subsets of my code, where
> > it's tangibly better for me if all objects default construct to the
> > most likely desired initial state (like vector<int> does), rather than
> > the fastest establishment of invariants (like both int and vector<int>
> > do as you pointed out). I don't know much about D or Rust yet, but I
> > do know they both do this.
>
> Is it really so hard to type "int_fast16_t x = INT_MIN;" if you need that
> "x" to be initialized? To me the issues of software development are
> always totally elsewhere.
>
> >
> > I naively thought "hey, allowing x = std::unspecified" (or x = void like
> > D) would be having the cake and eating it too, but I accept the wisdom
> > of others that this would do more harm than good. Many in my
> > particular industry have long abandoned pure C++, opting for a mix of C++
> > and something else (often lua or C#) I'm slowly & stubbornly realizing
> > that perhaps they're not all just crazy kids.
>
> The programming languages are software design tools. There's no
> point whatsoever to change C++ to be exactly like some other programming
> language. People who like C# or lua should use those instead of C++.

No argument. I didn't start this discussion with "change it, it's broken". I started it with "please help me understand why it's not broken". David Brown did exactly that.

I personally edit your "people who like C# or lua" to "people who need C# or lua".
This entire thread is about initializing, and why it is or isn't better for built-ins to be initialized to zero by default. No one is advocating that the option to leave uninitialized be taken away. It's a very important feature of the language.

>
> > For member x_, the few seconds it takes to initialize in the
> > required location is an insignficant non-issue much of the code I
> > write, but a tangible source of minor drag in other code I write. I
> > don't want to break the language to satisfy my desires in those
> > specific contexts, and I accept that the suggestion of "int x is zero
> > unless stated unspecified" would do just that.
>
> In C++ int is zero when it is stated to be zero.

and when declared with static storage, FYI.

>
> >
> > I think I just need a highly iterative language to sit on top of my
> > highly optimized language. Might not be D or Rust. I've done
> > nothing other than C++/C/ASM for my entire career, so other languages
> > are very new ground for me.
>
> If you need some sort of language to sit somewhere then put it to sit
> there.

Good advice.

flimfl...@gmail.com

unread,
Dec 22, 2015, 1:21:15 PM12/22/15
to
I think we find ourselves in a similar camp but for different reasons. I'm quite comfortable that I have enough tools to catch mistakes where I should have initialized and didn't (maybe I refactored the code and broke initialization, or I just plain forgot).

To me it's mostly an ergonomics issue, and only when I'm writing certain types of code that one might generalize as high-level scripting. Situations that are highly iterative and produce tons of code fast. I think I'm on a shrinking island of people who still use C++ this way. In these particular coding situations, the time it takes to visit the initialization sites shows up in my assessment of "what is measurably throttling my progress", and so I'd prefer the language to assign zero to int by default rather than some unknown-yet-still-valid value, the same way it assigns zero size to vector<int> by default rather than some unknown-yet-still-valid size.

This thread has convinced me that this is one of the lines marking divisions that I've heretofore refused to believe exist: Divisions between what C++ is good for and what Rust/D/others are good for.

flimfl...@gmail.com

unread,
Dec 22, 2015, 1:50:55 PM12/22/15
to
In highly iterative code, every time I use a std library type or one of my own types I am grateful I don't have to visit an initialization site before visiting the implementation site. Very often though, I truly have an int or a bool, not a counter<> or some other widget<>. It has crossed my mind more than once before to make "class Int" and "class Bool" to use in this type of script-y code. Perhaps I'm being too curmudgeonly here, but the very thought makes me nauseous.

Alf P. Steinbach

unread,
Dec 22, 2015, 5:57:21 PM12/22/15
to
On 12/16/2015 8:59 PM, flimfl...@gmail.com wrote:
> I've long wished C++ worked a bit like this:
>
> int x; // initialized to zero in all scopes (not just global)
>
> int y = std::undefined; // it's left uninitialized, only when I say so

This is a good idea, and you're not the first to air it.

A simple but unfortunately verbose interim solution is to define a
wrapper like this:

struct Not_initialized {};

template< class Type >
struct Initialized_
{
Type value;
Initialized_(): value() {}
Initialized_( Not_initialized ) {} // !
};

and e.g. definining

using Int = Initialized_<int>;

and then you should be able to write

Int x; // Inialized to 0.
Int y{ Not_initialized }; // But the = syntax may cause actions.

cout << x.value*y.value << endl;

Of course the name "value" could be replaced with e.g. just "_" to cut
down on the verbosity.

A more extreme measure for more concise code is to implement a basic
type replacement class, i.e. a type with arithmetic operators,
comparison etc. The Boost library has some help for that. In principle
it could be as efficient as direct use of the build-in type it replaces.


> struct Foo {
> Foo() { }
> Foo(std::undefined_t) : x_(std::undefined) { }
> int x_;
> };

One way to guarantee initialization of members is to make them "const",
at the cost of losing copy assignment.

Another way is to use one of the two wrapper types sketched above.


> struct Bar {
> Bar() { }
> int x_;
> };
>
>
> Foo foo; // foo.x_ is zero
> Foo foo = std::undefined; // foo.x_ is undefined

Well yes, in C++03 it was a problem how to zero-initialize a POD struct
local automatic /variable/.

Doing it for dynamic allocation or for a temporary was easy, e.g.

Pod* p = new Pod(); // Value-initialized = zero for POD, hurray!

But trying that for a local variable, like

Pod f();

would just declare a function f; it's the infamous "most vexing parse".

For a variable one could write

Pod o = Pod();

but that was very ugly and verbose.

Happily with C++11 you can just write

Pod o{}; // Yay, braces to the rescue!

>
> Bar bar; // bar.x_ is zero
> Bar bar = std::undefined; // compiler error
>
> I know there's at least a few of us out there who would welcome this
> sort of thing. I also know there's massive opposition to this from
> really smart people, and so I want to learn from you. If I could
> understand why it's better for built-ins to be undefined by default
> rather than by request, it would be a great help to me.

Those who argue that the current rules are bestest are presumably silly
conformists.

The current rules were good for early C, where it was the programmer's
job to do micro-optimizations, but they're not good for modern C++.

Due to its history C++ has a lot of defaults backwards for modern
programming. For example, it would IMO be much better if objects were
"const" by default, and had to be declared mutable to be, well, mutable.
At one time I also argued that methods (non-static member functions)
should better have been virtual by default, but I'm not so sure now: I
find that my own default now is non-virtual, that for me, now, there
must be a good /reason/ for a method to be virtual.


> Please keep in mind I'm asking for guidance completely separate from
> the issues of legacy code or precedent set by C. I understand many of
> those issues. I instead want to learn why it shouldn't be done even if
> C++ were being designed for the first time today. If I could get that
> through my thick head, I'd be very happy.

I agree completely with you, IMO there isn't any technical reason why a
new language today should be like that.

I think those who argue otherwise (you indicate that such exist), do it
just out of conformity, a misplaced idea of belonging in a group of
followers of X by strongly denying any slightest blemish of X.

On the other hand, retrofitting the zero-initialization on C++, in a way
where one could not opt out of it, could break time-critical code in
e.g. real time systems.


> Here's something that may help understand part of where I'm hung up: >
> int x; // undefined
> float x; // undefined
> void* x; // undefined
> std::vector<int> x; // well defined
> std::string x; // well defined
> std::shared_ptr<int> // well defined (empty shared_ptr)
>
> In a perfect world, why should they be different?

In a perfect world one would have to explicitly accept the dangers of
the nano-optimization.

Btw., the term you're looking for isn't "undefined".

It's "indeterminate value".


> I've read rationale that cites valgrind. I get why valgrind is great
> for catching uninitialized data bugs, but I'm not sure why it would
> matter to valgrind whether the lack of initialization was default or
> explicit.

A debugger can rely on certain well know bitpatterns indicating most
likely uninitialized variables, e.g. CCCC... hex.

The idea is to fill memory with that bitpattern, and detect that it
apparently hasn't been changed in a variable (especially pointer).

But arguing that uninitialized variables are good because it allows a
debugger to detect uninitialized variables, is not very convincing...


Cheers!, & hth.,

- Alf

PS: Sorry if much of what I wrote here has already been discussed. I've
been offline for a while and there was just too much in this thread.

flimfl...@gmail.com

unread,
Dec 22, 2015, 11:53:27 PM12/22/15
to
Thank you for the thoughtful response. Your perspective seems quite different than many of the responses I've gotten, and I appreciate it very much.

As far as why the current rules are not inconsistent, I received an excellent answer from David Brown. This is what I wanted most from this thread.

As far as why the current rules are superior and shouldn't be changed even if C++ were being designed today and was unencumbered by legacy precedent, you're spot on. All the non-religious, practical arguments seem centered around debug tools detecting unintentional behavior. I do get it - sometimes you'd get a default initialization that you didn't intend and the debugging tool couldn't know enough to flag it for you. I like how you put it - not very convincing. But it is a real bullet point in the "pro" column of current behavior. It avoids silently lost performance. OK - that's what C++ is about, I can get on board even if I wish it were different.

Probably my most unexpected take-away from my first interaction with comp.lang.c++ is that I really shouldn't be using C++ everywhere anymore. I've held onto that approach for way too long. It's certainly not just about default initialization of built-ins, but this issue alone was enough to show me that I'm expecting too much out of a single language in a world of increasingly complex software.

Ian Collins

unread,
Dec 23, 2015, 12:13:23 AM12/23/15
to
flimfl...@gmail.com wrote:
>
> As far as why the current rules are not inconsistent, I received an
> excellent answer from David Brown. This is what I wanted most from
> this thread.
>
> As far as why the current rules are superior and shouldn't be changed
> even if C++ were being designed today and was unencumbered by legacy
> precedent, you're spot on. All the non-religious, practical
> arguments seem centered around debug tools detecting unintentional
> behavior. I do get it - sometimes you'd get a default initialization
> that you didn't intend and the debugging tool couldn't know enough to
> flag it for you. I like how you put it - not very convincing. But
> it is a real bullet point in the "pro" column of current behavior.
> It avoids silently lost performance. OK - that's what C++ is about,
> I can get on board even if I wish it were different.

I agree with you and Alf that the arguments around tools spotting
uninitialised variables isn't very convincing. Tools shouldn't be
relied upon to spot these trivial errors, they should be picked up in
unit tests. Given only uninitialised fundamental types can be spotted,
there's a danger of falling into a false sense of security.

I'm on the fence regarding performance; I can see a situation where
performance critical code using lots of PODs would suffer badly, but
most of our classes use a mix of member types and the default
initialisation of one of these may be significantly more expensive than
a bunch of fundamental types.

I'm generally happy to use the new member initialisation syntax and/or
delegated constructors now, it doesn't require anywhere near the
discipline of constructor only initialisation. So in short, C++11 makes
unintentional uninitialised members much less of an issue.

> Probably my most unexpected take-away from my first interaction with
> comp.lang.c++ is that I really shouldn't be using C++ everywhere
> anymore. I've held onto that approach for way too long. It's
> certainly not just about default initialization of built-ins, but
> this issue alone was enough to show me that I'm expecting too much
> out of a single language in a world of increasingly complex
> software.

Indeed. Although I do use C++ just about everywhere :)

--
Ian Collins

Öö Tiib

unread,
Dec 23, 2015, 6:26:45 AM12/23/15
to
On Tuesday, 22 December 2015 19:52:48 UTC+2, flimfl...@gmail.com wrote:
> On Friday, December 18, 2015 at 10:13:07 PM UTC-7, Öö Tiib wrote:

...

> >
> > The programming languages are software design tools. There's no
> > point whatsoever to change C++ to be exactly like some other programming
> > language. People who like C# or lua should use those instead of C++.
>
> No argument. I didn't start this discussion with "change it, it's broken".
> I started it with "please help me understand why it's not broken". David
> Brown did exactly that.
>
> I personally edit your "people who like C# or lua" to "people who need C# or lua".

I still meant "like". I have demanded my algorithm to be rewritten in Java
(a man week) because 5 times loss of efficiency was unimportant (12
seconds or 60 in rarely used tool does not matter) compared to improved
maintainability and simplicity. Code base that needed the algorithm was
Java, future need for changes were likely and excellent performance of
my implementation was partly thanks to usage of containers from 'boost'.
Integrating C++ and Java can also take whole man-week.

...

> > In C++ you are not required to initialize anything.
>
> This entire thread is about initializing, and why it is or isn't better for
> built-ins to be initialized to zero by default. No one is advocating that
> the option to leave uninitialized be taken away. It's a very important
> feature of the language.

There are technically three schools:

A) Greedy school: when the value is unknown then leave it uninitialized
and let the tools track that it is not used uninitialized, it is cheapest.

B) Lazy school: when the value is unknown then initialize it with most
common value, it is most convenient.

C) Paranoid school: when the value is unknown then initialize it with
clearly incorrect value and check for it, the compilers and other tools
can fail to track down all corner cases.

I accept that all three schools have useful point. "A" is simplest since
performance is best reason to use C++. Why most terse syntax is
used for choice "A" is likely purely for legacy reasons. It leaves me
indifferent since I can type. For hypothetical new C++ like language
I would remove terse form whatsoever:

T x1 {void}; // uninitialized
T x2 {default]; // default-initialized (0 for int)
T x3 {nil}; // initialized to incorrect or missing state (syntax error for int if int does not have NaN)
T x4; // syntax error

woodb...@gmail.com

unread,
Dec 23, 2015, 3:18:30 PM12/23/15
to
C++ isn't perfect, but I think it can be improved upon.
My efforts are aimed at helping C++ gain more traction
in the area of serialization. Java has more than 4 times
as much text here

https://en.wikipedia.org/wiki/Serialization

as C++ does. I think if Java supporters want to keep
such a long description, they should be willing to move
Java after C++ and some other languages.

Brian
Ebenezer Enterprises - In G-d we trust.
http://webEbenezer.net

Ian Collins

unread,
Dec 23, 2015, 3:27:24 PM12/23/15
to
woodb...@gmail.com wrote:
>
> C++ isn't perfect, but I think it can be improved upon.

If you are going to bang your drum, at least snip all the context you
aren't interested in replying to!

--
Ian Collins

Jorgen Grahn

unread,
Dec 29, 2015, 7:25:08 AM12/29/15
to
> In highly iterative code,

I don't know what "iterative" means in this context, I'm afraid.
I was talking mostly about class members in the paragraph above,
because that's what David Brown did.

> every time I use a std library type or one
> of my own types I am grateful I don't have to visit an
> initialization site before visiting the implementation site. Very
> often though, I truly have an int or a bool, not a counter<> or some
> other widget<>.

Ok. Note the /sometimes/ above; I'm not claiming it applies to you.

Although I note that to a lot of people, my counters would "truly" be
integers, too. A common mistake among C++ programmers is that they use
the builtin types too much; their own classes are big, long-lived
things.

> It has crossed my mind more than once before to
> make "class Int" and "class Bool" to use in this type of script-y
> code. Perhaps I'm being too curmudgeonly here, but the very thought
> makes me nauseous.

Yes; such code would look very unusual.

Jorgen Grahn

unread,
Jan 1, 2016, 8:40:45 AM1/1/16
to
On Wed, 2015-12-23, flimfl...@gmail.com wrote:

> Probably my most unexpected take-away from my first interaction with
> comp.lang.c++ is that I really shouldn't be using C++ everywhere
> anymore. I've held onto that approach for way too long. It's
> certainly not just about default initialization of built-ins, but
> this issue alone was enough to show me that I'm expecting too much
> out of a single language in a world of increasingly complex
> software.

I'm not sure software necessarily grows more complex ... but it
doesn't matter; there have always been good reasons to use multiple
languages.

Where I come from -- Unix -- we had shell scripts as first-class
citizens from the very beginning. Then Perl etc showed up. Plus
all the domain-specific languages.

Personally, I don't see a need for more than C++ in the "static strong
typing" category. But if you want something for rapid prototyping (I
suspect that was what your "iterative style" meant), check out Python
or Ruby.
0 new messages