Topic: Eliminating uninitialised variables


Author: usenet-nospam@nmhq.net (Niklas Matthies)
Date: Mon, 25 Oct 2004 18:22:52 GMT
Raw View
On 2004-09-21 05:24, Dave Harris wrote:
:
> The efficiency issue we can probably handle by providing a way to request
> uninitialised variables explicitly. Eg reusing the keyword "void":
>     int x; // x is 0.
>     int y = void; // y is uninitialised.
>
> The important cases are arrays:
>     int array[1000] = void;
>
> especially when they are instance variables:
>
>      struct S {
>          int array[1000];
>          S() : array(void) {}
>      };
>
> I'm not wedded to this particular syntax.

I'd suggest '?' (question mark) instead of 'void'. E.g.:

   int x = ?;

   struct S
   {
      int array[1000];
      S() : array(?) { }
   };

-- Niklas Matthies

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: esben@despammed.com (Esben Mose Hansen)
Date: Fri, 8 Oct 2004 20:22:49 GMT
Raw View
Peter van Merkerk wrote:

> Stephen Howe wrote:

>> I have to say in the past 5 years, I have not been bitten once by
>> "uninitialised variables".

> That doesn't mean there aren't any in the code you written, and it might
> surface at the worst possible time. The problem with uninitialized
> variables is that the code may work just fine on your system, and pass
> all tests and yet blow up in the face of the customer. If you lurk
> around newsgroups you do see every now and then people asking why debug
> builds work fine and release builds fail miserably. This is typically
> caused by uninitialized variables.

http://valgrind.kde.org/ would be your friend, here. As a bonus, your code
get tested for memory leaks, too.

Once upon a time, it was said that one tool should do one job only. Now a
days compilers seems to be required to do some (rather poor) linting as
well. Why is this?

--
mvh. Esben Mose Hansen
homepage: www.mosehansen.dk --xxx-- GPG fingerprint:
www.mosehansen.dk/about.html

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: merkerk@deadspam.com (Peter van Merkerk)
Date: Mon, 11 Oct 2004 18:20:26 GMT
Raw View
Esben Mose Hansen wrote:
> Peter van Merkerk wrote:
>
>
>>Stephen Howe wrote:
>
>
>>>I have to say in the past 5 years, I have not been bitten once by
>>>"uninitialised variables".
>
>>That doesn't mean there aren't any in the code you written, and it might
>>surface at the worst possible time. The problem with uninitialized
>>variables is that the code may work just fine on your system, and pass
>>all tests and yet blow up in the face of the customer. If you lurk
>>around newsgroups you do see every now and then people asking why debug
>>builds work fine and release builds fail miserably. This is typically
>>caused by uninitialized variables.
>
> http://valgrind.kde.org/ would be your friend, here. As a bonus, your code
> get tested for memory leaks, too.

AFAIK valgrind does not do static code analysis, only run-time checking
and only on one platform. It may be a valuable tool if you happen to be
using that platform. Run-time checks (valgrind is only one of a great
many tools for this) have their limitations since it won't detect errors
in code that doesn't get executed. It is however no replacement for
static code analysis (such as lint).

> Once upon a time, it was said that one tool should do one job only. Now a
> days compilers seems to be required to do some (rather poor) linting as
> well. Why is this?

A compiler is no replacement for a static code analysis tool, but that
is not the point of this discussion. The point being discussed here is
should C++ continue to default to unpredicatable behaviour or not?

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Sun, 26 Sep 2004 16:06:03 GMT
Raw View
rmaddox@isicns.com (Randy Maddox) wrote (abridged):
> Do we even need to do anything about this?  As other posters have
> pointed out there are situations in which uninitialized variables are
> normal, expected and not a problem.

That is why I suggested syntax for leaving variables uninitialised
explicitly, when that is what the programmer intends.


> Also, don't most compilers do a good job of warning about
> uninitialized variables, if the warning level is set high enough
> at least?

I don't believe so. Some manage it in easy cases, eg for local variables,
but it's hard to do well (eg) for class instance variables without also
warning for the legitimate cases you mention above. There is currently no
portable syntax for the programmer to indicate their intent.


> Once the compiler warns it's up to the developer to decide if it is
> a problem or not and take corrective action if and as necessary.

If it's not a problem, there is no (portable) corrective action available
to prevent the warning for that particular case. And in my view,
production code should compile clean, with no compiler warnings
whatsoever. Your approach would require me to initialise variables always,
even though uninitialised variables are sometimes required for correctness
and efficiency.

Clearly, the crucial idea is to have the __uninitialised syntax or
similar. Given that, it seems to me we have 3 choices:

    (1) Using a variable which is implicitly or explicitly
    uninitialised remains undefined behaviour in both cases.
    Compilers are encouraged to warn about the implicit case,
    but are not required to.

    (2) Using a variable which is explicitly uninitialised is
    undefined behaviour. A program which may use a variable which
    is implicitly uninitialised is ill-formed; a compile-time
    diagnostic is required.

    (3) Using a variable which is explicitly uninitialised is
    undefined behaviour. Variables which are implicitly
    uninitialised are default/zero-initialised.

(By "using" I think I mean an l-value to r-value conversion; I certainly
don't mean an assignment to the variable. I'm not aiming for precise
legalese at this stage.)

(1) is the smallest, least problematic change. It does not affect the
correctness or efficiency of existing code. It still allows compilers to
detect uninitialised variables at run-time  We can start with (1) and move
to (2) or (3) later. The disadvantage is that it leaves it up to the
compiler vendor.

(2) has two problems. First, it breaks existing code. The break is not
silent and is easy to fix by adding __uninitialised. The broken code is
probably buggy anyway, but might be OK, eg, if it is never executed.

Second, it requires us to nail down the exact forms of code that must
produce a diagnostic. This will add quite a lot of verbiage to the
standard - I guess a page or so. For example, does:
    enum { Red, Blue, Green } colour = Red;
    int x;
    switch (colour) {
    case Red:
    case Blue:
    case Green:
        x = 0;
    default:
        use(x);
    }

require a diagnostic? What if the initialisation of colour isn't visible?
What if "Green" is deleted, so the enum's range is 0-1 instead of 0-3?

(3) also has two problems. First, it affects the efficiency of existing
code. Some code will silently get default initialisation when it doesn't
need it. The loss of efficiency will be silent and unobvious (it will
often depend on the quality of the optimiser). In most cases it will be
too small to show up in a profiler. You can fix it by adding
__uninitialised.

Second, there may be a long transition period in which some compilers
conform to the new standard and others do not. If a programmer relies on
the new default initialisation, their code will silently break if they
switch to an older compiler that doesn't yet provide it. In practice this
probably means programmers will be reluctant to take advantage of the new
default initialisation - but they will still benefit from the removal of
undefined behaviour.


In my view (2) is a non-starter. It's not worth breaking existing code or
writing all the verbiage the standard would need. My initial proposal was
(3) and I still think this is good, but I am bothered by the potential
loss of efficiency. I would be content with (1).

-- Dave Harris, Nottingham, UK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: "Stephen Howe" <sjhoweATdialDOTpipexDOTcom@eu.uu.net>
Date: Mon, 27 Sep 2004 16:55:38 GMT
Raw View
> We can't require the compiler to reject (at compile time) accesses of
> uninitialised variables without breaking existing code, so I think we
> would instead have to require all variables to be initialised -
> zero-initialised as if they were statics.

And does zero-initialising mean that the program is correct or will behave
more correctly? No.
I don't see that this gains anything.

I have to say in the past 5 years, I have not been bitten once by
"uninitialised variables".
It is not a signicant problem to me.

Stephen Howe




---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Tue, 28 Sep 2004 13:52:57 GMT
Raw View
brangdon@cix.co.uk (Dave Harris) wrote in message
news:<memo.20040922084130.2520A@brangdon.m>...

> > I don't think it is worth doing. Zero-initialization doesn't really
> > make sense for object type members, anyway.

I think it isn't so much a question of getting a useful initialization.
It's more a question of getting something repeatable -- if 0 isn't any
good, then your code will fail systematically, and not just at odd
moments when you aren't looking.

I think in some ways this would be like specifying the order of
evaluation in an expression.  I don't think that good code would take
advantage of it, even if it were guaranteed; it's too subtle, and a
reader is too likely to miss the point.  On the other hand, it makes
whatever was written a good deal more reproduceable; if there is an
error, there is always the same error.

> Perhaps I used the wrong phrase. I meant the kind of initialisation
> static objects get. For built-in types, that's as if they were
> initialised from zero. Of course the final bit-pattern may not be
> zero, and of course user-defined types have their default
> constructors.

The only problem I see is how to define this initialization with regards
to references.  We all know that in practice, depending on context and
the compiler, a reference either occupies no memory, or it is a pointer;
neither pose a problem for the proposition.  But the standard doesn't
know this, and I can't figure out how to word your requirement for
references.

Or course, since a reference MUST be initialized anyway, it is probably
sufficient to say that they aren't included in the guarantee.

For the rest, I'm all for it.  (I'd prefer requiring a trap of some sort
when an uninitialized variable is accessed, but I don't think that is
very realistic; it wouldn't be very easy or very cheap to implement on
the majority of hardware.)

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Peter van Merkerk <merkerk@deadspam.com>
Date: Tue, 28 Sep 2004 13:53:11 GMT
Raw View
Stephen Howe wrote:

>>We can't require the compiler to reject (at compile time) accesses of
>>uninitialised variables without breaking existing code, so I think we
>>would instead have to require all variables to be initialised -
>>zero-initialised as if they were statics.
>
> And does zero-initialising mean that the program is correct or will behave
> more correctly? No.

It would lead to more predictable (not necessarilly correct) behavior.
It doesn't fix bugs, but it would simplify locating them.

> I don't see that this gains anything.
>
> I have to say in the past 5 years, I have not been bitten once by
> "uninitialised variables".

That doesn't mean there aren't any in the code you written, and it might
surface at the worst possible time. The problem with uninitialized
variables is that the code may work just fine on your system, and pass
all tests and yet blow up in the face of the customer. If you lurk
around newsgroups you do see every now and then people asking why debug
builds work fine and release builds fail miserably. This is typically
caused by uninitialized variables.

> It is not a signicant problem to me.

Your (or mine) experiences are not necessarily representative for the
rest of the world.

--
Peter van Merkerk
peter.van.merkerk(at)dse.nl

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Tue, 28 Sep 2004 13:53:18 GMT
Raw View
sean@f4.ca (Sean Kelly) wrote in message
news:<c628f43d.0409231543.397b1c09@posting.google.com>...
> walter@digitalmars.nospamm.com ("Walter") wrote in message
> news:<aRm4d.348315$8_6.249357@attbi_s04>...

> > It's too bad there is no NaN pattern for integer types. Even better
> > would be a memory bit per location that could be set to
> > "uninitialized" which would cause a trap if that location was
> > read. I wonder some times how many latent bugs of this nature are in
> > shipping applications <g>.

> The standard does leave room for trap values, though I haven't
> encountered a compiler that uses them.  My only concern with having
> C++ default initialize primitives to a NaN-like value is that it would
> silently break a lot of code that relies on current default
> constructor behavior (ie. set to zero).  Quite nice for D, but it may
> be too late for C++.

The current situation is that accessing an uninitialized object is
undefined behavior.  Zero initialization only applies to statics.

Many years back, I imagined an ideal hardware: it used 1's complement,
and never generated a negative 0.  Any read of an object with all one
bits would trigger a trap.  Manipulating the stack pointer caused any
newly accessible memory to be initialized with all one bits.

In practice, today, there are no trapping representations for integral
types.  In practice, too, null pointers and 0.0 floating points are
generally all bits 0.  Initialization with 0's is thus simple and easy
for the implementation.  And I'd prefer all types initialized with 0 to,
say, int's initialized with 0 but floating points with trapping values.
I'd prefer everything to trap, but that not being reasonable, I'd prefer
consistency -- everything follows the same rules.

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kanze@gabi-soft.fr
Date: Tue, 28 Sep 2004 13:53:26 GMT
Raw View
brangdon@cix.co.uk (Dave Harris) wrote in message
news:<memo.20040922212121.2520E@brangdon.m>...

    [...]
> > 4 What about volatile?

> Good question. I hadn't thought about it, but I don't think it causes any
> new problems. These:

>     // Proposed
>     volatile int x;
>     volatile int x( __uninitialised );

> under the new regime would have the semantics of:

>     // Current
>     volatile int x( 0 );
>     volatile int x;

> under the current regime - whatever semantics those happen to be.

Which means that you've introduced a quiet change, which could seriously
break user code.

I don't know if it is really a problem.  In all of the cases of memory
mapped IO I've seen, the access has been through a pointer to volatile
anyway (generally due to the fact that such memory must be at specific
addresses, and casting an int to a pointer was the easiest way of
achieving this).

--
James Kanze           GABI Software         http://www.gabi-soft.fr
Conseils en informatique orient   e objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place S   mard, 78210 St.-Cyr-l'   cole, France, +33 (0)1 30 23 00 34

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Tue, 28 Sep 2004 18:56:07 GMT
Raw View
sjhoweATdialDOTpipexDOTcom@eu.uu.net (Stephen Howe) wrote (abridged):
> And does zero-initialising mean that the program is correct or will
> behave more correctly?

In many cases, yes. It at least makes the behaviour consistent, so that
the problem is easier to track down.


> I have to say in the past 5 years, I have not been bitten once by
> "uninitialised variables".
> It is not a signicant problem to me.

Data point noted. I'm guessing you're a relatively experienced programmer?

I've been bitten by it, mainly in code written by other people. In
particular with IEEE doubles, which sometimes became signalling NaNs in
release mode. As I recall, the code which read them was a
copy-constructor. It didn't matter what their value was so long as they
could be read without the access throwing an exception, so in this case
zero-initialisation would have been fine. Whether they threw depended on
the history of the heap, so it was quite hard to debug. I was using a
compiler which initialises heap to a known state in debug releases, which
masked the problem further.


> I don't see that this gains anything.

I hope I have now convinced you otherwise. In my view, eliminating
potential undefined behaviour always has some benefit; the question is
whether the benefit is worth the cost. And in this case I think the cost
can be made small.

-- Dave Harris, Nottingham, UK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: John Nagle <nagle@animats.com>
Date: Tue, 28 Sep 2004 18:56:17 GMT
Raw View
kanze@gabi-soft.fr wrote:

> sean@f4.ca (Sean Kelly) wrote in message
> news:<c628f43d.0409231543.397b1c09@posting.google.com>...
>
>>walter@digitalmars.nospamm.com ("Walter") wrote in message
>>news:<aRm4d.348315$8_6.249357@attbi_s04>...
>
>
>>>It's too bad there is no NaN pattern for integer types.
...

>>The standard does leave room for trap values, though I haven't
>>encountered a compiler that uses them.

     Such things have been done.  Look at the numeric representations
of the Burroughs 5500, circa 1962, and its successors.  Those
were signed-magnitude machines with an integrated integer/floating
point representation.

    John Nagle
    Animats

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: walter@digitalmars.nospamm.com ("Walter")
Date: Wed, 22 Sep 2004 17:15:45 GMT
Raw View
"John Nagle" <nagle@animats.com> wrote in message
news:FQO3d.21860$bB7.16246@newssvr27.news.prodigy.com...
>     I'd suggest allowing initial values within class
> declarations, as in
>
> class T {
> char* p = 0;
> };
>
>     Yes, you can do the same thing in each constructor's
> initialization section.  But it's not as obvious by
> examination when someone left out an initialization,
> because the initialization and declaration are at
> different places.

This is the approach D takes. It makes sense to put the default value where
the declaration is, not off somewhere else.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: sean@f4.ca (Sean Kelly)
Date: Wed, 22 Sep 2004 17:16:26 GMT
Raw View
brangdon@cix.co.uk (Dave Harris) wrote in message news:<memo.20040920104138.384A@brangdon.m>...
> In a comp.lang.c++.moderated thread about const correctness, the issue of
> uninitialised variables came up. Accessing an uninitialised variable is a
> source of undefined behaviour which requires constant programmer vigilance
> to avoid. A mistake often leads to real bugs or crashes, which can be
> irreproducible and so hard to track down.
>
> Can we do something constructive towards fixing this? Has it been tried;
> are there known problems? Here are my initial thoughts.

Much of the discussion centered initialization problems in classes.
Specifically, missing an initialization among what may be a large
collection of contructors.  This problem will likely be reduced by
fowarding contructors, but is still worth addressing.  It seems the
simplest solution would be to adjust the wording of 12.6 to include
primitive types.

> We can't require the compiler to reject (at compile time) accesses of
> uninitialised variables without breaking existing code, so I think we
> would instead have to require all variables to be initialised -
> zero-initialised as if they were statics. Since accessing an uninitialised
> variable is currently undefined behaviour, a conforming program could not
> tell the difference. I can think of two possible objections:
>
> (1) A good compiler could use the undefined behaviour to detect accidents
> at run-time, by secretly initialising to a trapping value.

My suggestion above would imply default initialization, but I suppose
this is another option.

> (2) Efficiency.

Static arrays are probably the strongest argument against default
initialization (since pointers could be considered initialized simply
by assigning nullptr), but perhaps a means to opt-out would be
sufficient?  And if so, where does this leave classes (which obviously
must be initialized)?  Is the lack of consistency acceptable?

> The efficiency issue we can probably handle by providing a way to request
> uninitialised variables explicitly. Eg reusing the keyword "void":
>     int x; // x is 0.
>     int y = void; // y is uninitialised.
>
> The important cases are arrays:
>     int array[1000] = void;

Default initialization across the board is a larger issue, though I
suppose it's worth considering for the sake of consistency.  Still, I
suspect there are fewer initialization oversights in standard
functions.


Sean

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Wed, 22 Sep 2004 17:47:56 GMT
Raw View
invalid@bigfoot.com (Bob Hairgrove) wrote (abridged):
> It would be fairly easy to require either malloc or operator new to
> zero-initialize all storage it allocates.

If operator new is written by the user, such a requirement would break
backwards compatibility.


> >What else am I missing? This is surely the kind of thing which future
> >revisions of the C++ standard should be considering.
>
> I don't think it is worth doing. Zero-initialization doesn't really
> make sense for object type members, anyway.

Perhaps I used the wrong phrase. I meant the kind of initialisation static
objects get. For built-in types, that's as if they were initialised from
zero. Of course the final bit-pattern may not be zero, and of course
user-defined types have their default constructors.

-- Dave Harris, Nottingham, UK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Wed, 22 Sep 2004 19:40:57 GMT
Raw View
pasa@lib.hu ("Balog Pal") wrote (abridged):
> In an old version of this thread the idea I liked the most was having
>
> int  item = __uninitialised;
> int  item(__uninitialised);

Which is the same apart from the spelling of __uninitialised. I'd prefer
something short that didn't begin with __, but OK.


> You forget C++-level zero-init is not a binary zero fill.  zero and null
> vlaues may come with whatever bit patterns, and they in fact do for
> doubles.

I'm not forgetting that. It's one of the reasons I think this should be
quality of implementation - because not all implementations would benefit
from an infrastructure to tag memory known to be zero-filled. However, in
practice a great many would benefit if such tagging were possible, behind
the scenes.

I'm pretty sure IEEE allows all bits 0 for 0.0, but whatever. I'd expect
an implementation to fill the entire memory block with 0s first, then
overwrite any non-0 values afterwards - perhaps during construction, at
the same time that vtable pointers are installed.

-- Dave Harris, Nottingham, UK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: comeau@panix.com (Greg Comeau)
Date: Wed, 22 Sep 2004 20:29:48 GMT
Raw View
In article <6x14d.132741$3l3.96020@attbi_s03>,
Walter <walter@digitalmars.nospamm.com> wrote:
>
>"John Nagle" <nagle@animats.com> wrote in message
>news:FQO3d.21860$bB7.16246@newssvr27.news.prodigy.com...
>>     I'd suggest allowing initial values within class
>> declarations, as in
>>
>> class T {
>> char* p = 0;
>> };
>>
>>     Yes, you can do the same thing in each constructor's
>> initialization section.  But it's not as obvious by
>> examination when someone left out an initialization,
>> because the initialization and declaration are at
>> different places.
>
>This is the approach D takes. It makes sense to put the default value where
>the declaration is, not off somewhere else.

What does D do if it's also specified on a constructor (or multiple
ones with different values), assuming is has such possibilities?
--
Greg Comeau / Comeau C++ 4.3.3, for C++03 core language support
Comeau C/C++ ONLINE ==>     http://www.comeaucomputing.com/tryitout
World Class Compilers:  Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Wed, 22 Sep 2004 20:29:55 GMT
Raw View
news0@nospam.demon.co.uk (John G Harris) wrote (abridged):
> 1 Are there any compilers that make a good job of warning about the use
> of uninitialised variables? If there are then surely that's a better
> solution.

It is legitimate to have uninitialised variables, so long as they are not
accessed, so I don't think the compiler should warn about them. I have
seen classes where an initialised variable is used to guard access to
potentially uninitialised ones. An extreme example:

    class Stack{
        int array[10000];
        int top;
    public:
        Stack() : top(0) {}

        void push( int x ) { array[top++] = x; }
        int pop() { return array[--top]; }
    };

Here the array contents are not initialised, but I don't think the
compiler should warn about it. We can't reasonably expect the compiler to
figure out what the code is doing at run-time. In general that could
involve solving the Halting Problem.


> 2 Why is zero a better junk value than any other junk value?

I am not suggesting a junk value. I am suggesting code like:

    int *get() {
        int *result;
        if (condition())
            result = value();
        return result;
    }

would become well-defined and reasonable practice. It would return 0 when
condition() is false. I think 0 is the most useful and natural value, not
least because it is legal for so many built-in types (especially
pointers). Also because it is already used for static variables.


> 3 Wouldn't it be simpler to say that all stack space and all heap space
> is zeroed before (re-)use?

How does that differ from what I said? Are you assuming the bit-pattern of
all-zeros is a valid representation for all built-in types? Whose
responsibility is it to zero the memory? How do I avoid the zeroing if I
have a legitimate performance reason?


> 4 What about volatile?

Good question. I hadn't thought about it, but I don't think it causes any
new problems. These:

    // Proposed
    volatile int x;
    volatile int x( __uninitialised );

under the new regime would have the semantics of:

    // Current
    volatile int x( 0 );
    volatile int x;

under the current regime - whatever semantics those happen to be. I do
think that volatile is a compelling reason for supporting __uninitialised
(or equivalent). Avoiding superfluous memory writes can be a matter of
correctness as well as performance.

-- Dave Harris, Nottingham, UK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: walter@digitalmars.nospamm.com ("Walter")
Date: Wed, 22 Sep 2004 22:42:58 GMT
Raw View
"Greg Comeau" <comeau@panix.com> wrote in message
news:cismjo$5pr$1@panix2.panix.com...
> In article <6x14d.132741$3l3.96020@attbi_s03>,
> Walter <walter@digitalmars.nospamm.com> wrote:
> >
> >"John Nagle" <nagle@animats.com> wrote in message
> >news:FQO3d.21860$bB7.16246@newssvr27.news.prodigy.com...
> >>     I'd suggest allowing initial values within class
> >> declarations, as in
> >>
> >> class T {
> >> char* p = 0;
> >> };
> >>
> >>     Yes, you can do the same thing in each constructor's
> >> initialization section.  But it's not as obvious by
> >> examination when someone left out an initialization,
> >> because the initialization and declaration are at
> >> different places.
> >
> >This is the approach D takes. It makes sense to put the default value
where
> >the declaration is, not off somewhere else.
>
> What does D do if it's also specified on a constructor (or multiple
> ones with different values), assuming is has such possibilities?

If an initialization of it is done in the constructor, it overrides the
default specified in the member declaration. Also, constructors can call
each other, making it practical to make 'layered' constructors.

One interesting aspect of this is that it behaves as if all the members have
their default values before even entering the constructor, this means that
if the constructor references a member before the constructor initializes
it, it still will get a predictable value (the default for that member)
rather than garbage.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: comeau@panix.com (Greg Comeau)
Date: Thu, 23 Sep 2004 06:18:46 GMT
Raw View
In article <1GKClHFePJUBFwoH@jgharris.demon.co.uk>,
John G Harris <news0@nospam.demon.co.uk> wrote:
>2 Why is zero a better junk value than any other junk value?

IMO, it is sometimes not even a good non-junk value :)
--
Greg Comeau / Comeau C++ 4.3.3, for C++03 core language support
Comeau C/C++ ONLINE ==>     http://www.comeaucomputing.com/tryitout
World Class Compilers:  Breathtaking C++, Amazing C99, Fabulous C90.
Comeau C/C++ with Dinkumware's Libraries... Have you tried it?

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: walter@digitalmars.nospamm.com ("Walter")
Date: Thu, 23 Sep 2004 06:18:59 GMT
Raw View
"Dave Harris" <brangdon@cix.co.uk> wrote in message
news:memo.20040922200512.2520C@brangdon.m...
> I'm pretty sure IEEE allows all bits 0 for 0.0, but whatever.

It does. All bits 0 is +0.0 for IEEE 754 floating point encodings.

D, however, default initializes floating point values to the NaN bit
pattern, not 0. This has bug finding advantages because it causes the
programmer to have to think about what value it should be initialized to,
rather than inadvertantly using 0.0 which may become a hidden bug.

It's too bad there is no NaN pattern for integer types. Even better would be
a memory bit per location that could be set to "uninitialized" which would
cause a trap if that location was read. I wonder some times how many latent
bugs of this nature are in shipping applications <g>.

-Walter
www.digitalmars.com free C/C++/D compilers

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Thu, 23 Sep 2004 16:31:43 GMT
Raw View
nagle@animats.com (John Nagle) wrote (abridged):
>     I'd suggest allowing initial values within class
> declarations, as in
>
>  class T {
>   char* p = 0;
>   };
>
>     Yes, you can do the same thing in each constructor's
> initialization section.  But it's not as obvious by
> examination when someone left out an initialization,
> because the initialization and declaration are at
> different places.

That might be nice, but I see it as a separate issue; we still have to
consider what happens if someone forgets initialisation entirely.

(I think it's a fairly complex issue, too, once you consider order of
initialisation, user-defined types, exceptions, string literals etc.)

-- Dave Harris, Nottingham, UK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: hyrosen@mail.com (Hyman Rosen)
Date: Thu, 23 Sep 2004 16:32:32 GMT
Raw View
Dave Harris wrote:
> It is legitimate to have uninitialised variables, so long as they are not accessed

In fact, there are useful algorithms that access uninitialised data.
They work fine under the assumption that an uninitialised variable
contains some arbitrary value which stays until explicitly set.

     // A set of integers between 0 and N - 1
     template<unsigned N> struct set
     {
         unsigned dense[N], sparse[N], count;
         set() : count(0) { }
         bool has(unsigned k)
         { return k < N && sparse[k] < count && dense[sparse[k]] == k; }
         void ins(unsigned k)
         { if (k < N && !has(k)) { dense[count] = k; sparse[k] = count++; } }
         void del(unsigned k)
         { if (has(k)) { sparse[dense[sparse[k]] = dense[--count]] = sparse[k]; } }
         void clear() { count = 0; }
     };

In the above code, the membership test happily reads uninitialised data
from both arrays, but the algorithm is correct. That initialization and
emptying can be done in constant time is the main feature of this data
structure over, say, a bit vector.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: sean@f4.ca (Sean Kelly)
Date: Fri, 24 Sep 2004 00:04:11 GMT
Raw View
walter@digitalmars.nospamm.com ("Walter") wrote in message news:<aRm4d.348315$8_6.249357@attbi_s04>...
>
> It's too bad there is no NaN pattern for integer types. Even better would be
> a memory bit per location that could be set to "uninitialized" which would
> cause a trap if that location was read. I wonder some times how many latent
> bugs of this nature are in shipping applications <g>.

The standard does leave room for trap values, though I haven't
encountered a compiler that uses them.  My only concern with having
C++ default initialize primitives to a NaN-like value is that it would
silently break a lot of code that relies on current default
constructor behavior (ie. set to zero).  Quite nice for D, but it may
be too late for C++.


Sean

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: rmaddox@isicns.com (Randy Maddox)
Date: Fri, 24 Sep 2004 16:49:21 GMT
Raw View
brangdon@cix.co.uk (Dave Harris) wrote in message news:<memo.20040920104138.384A@brangdon.m>...
> In a comp.lang.c++.moderated thread about const correctness, the issue of
> uninitialised variables came up. Accessing an uninitialised variable is a
> source of undefined behaviour which requires constant programmer vigilance
> to avoid. A mistake often leads to real bugs or crashes, which can be
> irreproducible and so hard to track down.
>
> Can we do something constructive towards fixing this? Has it been tried;
> are there known problems? Here are my initial thoughts.
>

    [snip]

Do we even need to do anything about this?  As other posters have
pointed out there are situations in which uninitialized variables are
normal, expected and not a problem.  Also, don't most compilers do a
good job of warning about uninitialized variables, if the warning
level is set high enough at least?  Once the compiler warns it's up to
the developer to decide if it is a problem or not and take corrective
action if and as necessary.  Do we really need anything more than
that?

Randy.

>
> -- Dave Harris, Nottingham, UK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: brangdon@cix.co.uk (Dave Harris)
Date: Mon, 20 Sep 2004 23:24:35 CST
Raw View
In a comp.lang.c++.moderated thread about const correctness, the issue of
uninitialised variables came up. Accessing an uninitialised variable is a
source of undefined behaviour which requires constant programmer vigilance
to avoid. A mistake often leads to real bugs or crashes, which can be
irreproducible and so hard to track down.

Can we do something constructive towards fixing this? Has it been tried;
are there known problems? Here are my initial thoughts.

We can't require the compiler to reject (at compile time) accesses of
uninitialised variables without breaking existing code, so I think we
would instead have to require all variables to be initialised -
zero-initialised as if they were statics. Since accessing an uninitialised
variable is currently undefined behaviour, a conforming program could not
tell the difference. I can think of two possible objections:

(1) A good compiler could use the undefined behaviour to detect accidents
at run-time, by secretly initialising to a trapping value.

(2) Efficiency.

The efficiency issue we can probably handle by providing a way to request
uninitialised variables explicitly. Eg reusing the keyword "void":
    int x; // x is 0.
    int y = void; // y is uninitialised.

The important cases are arrays:
    int array[1000] = void;

especially when they are instance variables:

     struct S {
         int array[1000];
         S() : array(void) {}
     };

I'm not wedded to this particular syntax. The point is that leaving a
variable uninitialised is an optimisation that should be requested
manually. (In many cases, of course, the compiler can optimise out
redundant zero-initialisation without help.)

A compiler could trade speed for safety by using trapping values for void,
but I doubt that deals with the issue raised in (1). The concern is with
cases where:

(a) A programmer adds a new variable to a class.
(b) The programmer forgets to update a constructor, so it gets
zero-initialised.
(c) Zero-initialisation is not sufficient to satisfy the class invariant.

Personally I don't consider this serious enough to block the proposal. I
don't even know of an implementation which does use trapping values to
catch cases like this at run time. Comments?

Other points... with Java the zero-initialisation of a derived class
happens before the base class's constructor is run. I think this should be
permitted in C++, but I'm not sure it should be required. On the other
hand, it probably does no harm and I expect most implementations will want
to zap the whole memory block in one operation anyway.

Zeros are cheaper when bought in bulk, especially if they can be produced
in idle time, and especially if the O/S makes them. So it would be nice if
we could make zero-initialisation the responsibility of the memory manager
rather than the class's constructor. However, I don't see how to achieve
this without breaking backwards compatibility. Probably it should be a
quality of implementation issue anyway.

This would be a difference in behaviour between C++ and C. I don't think
it will cause problems, but perhaps someone with more experience will
comment.

What else am I missing? This is surely the kind of thing which future
revisions of the C++ standard should be considering.

-- Dave Harris, Nottingham, UK

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: nagle@animats.com (John Nagle)
Date: Tue, 21 Sep 2004 13:05:04 GMT
Raw View
    I'd suggest allowing initial values within class
declarations, as in

 class T {
  char* p = 0;
  };

    Yes, you can do the same thing in each constructor's
initialization section.  But it's not as obvious by
examination when someone left out an initialization,
because the initialization and declaration are at
different places.

   John Nagle
   Animats

Dave Harris wrote:
> In a comp.lang.c++.moderated thread about const correctness, the issue of
> uninitialised variables came up.

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: invalid@bigfoot.com (Bob Hairgrove)
Date: Tue, 21 Sep 2004 17:37:15 GMT
Raw View
On Mon, 20 Sep 2004 23:24:35 CST, brangdon@cix.co.uk (Dave Harris)
wrote:

>In a comp.lang.c++.moderated thread about const correctness, the issue of
>uninitialised variables came up. Accessing an uninitialised variable is a
>source of undefined behaviour which requires constant programmer vigilance
>to avoid. A mistake often leads to real bugs or crashes, which can be
>irreproducible and so hard to track down.
>
>Can we do something constructive towards fixing this? Has it been tried;
>are there known problems? Here are my initial thoughts.
>
>We can't require the compiler to reject (at compile time) accesses of
>uninitialised variables without breaking existing code, so I think we
>would instead have to require all variables to be initialised -
>zero-initialised as if they were statics. Since accessing an uninitialised
>variable is currently undefined behaviour, a conforming program could not
>tell the difference. I can think of two possible objections:
>
>(1) A good compiler could use the undefined behaviour to detect accidents
>at run-time, by secretly initialising to a trapping value.
>
>(2) Efficiency.
>
>The efficiency issue we can probably handle by providing a way to request
>uninitialised variables explicitly. Eg reusing the keyword "void":
>    int x; // x is 0.
>    int y = void; // y is uninitialised.
>
>The important cases are arrays:
>    int array[1000] = void;
>
>especially when they are instance variables:
>
>     struct S {
>         int array[1000];
>         S() : array(void) {}
>     };
>
>I'm not wedded to this particular syntax. The point is that leaving a
>variable uninitialised is an optimisation that should be requested
>manually. (In many cases, of course, the compiler can optimise out
>redundant zero-initialisation without help.)
>
>A compiler could trade speed for safety by using trapping values for void,
>but I doubt that deals with the issue raised in (1). The concern is with
>cases where:
>
>(a) A programmer adds a new variable to a class.
>(b) The programmer forgets to update a constructor, so it gets
>zero-initialised.
>(c) Zero-initialisation is not sufficient to satisfy the class invariant.
>
>Personally I don't consider this serious enough to block the proposal. I
>don't even know of an implementation which does use trapping values to
>catch cases like this at run time. Comments?
>
>Other points... with Java the zero-initialisation of a derived class
>happens before the base class's constructor is run. I think this should be
>permitted in C++, but I'm not sure it should be required. On the other
>hand, it probably does no harm and I expect most implementations will want
>to zap the whole memory block in one operation anyway.
>
>Zeros are cheaper when bought in bulk, especially if they can be produced
>in idle time, and especially if the O/S makes them. So it would be nice if
>we could make zero-initialisation the responsibility of the memory manager
>rather than the class's constructor. However, I don't see how to achieve
>this without breaking backwards compatibility. Probably it should be a
>quality of implementation issue anyway.

It would be fairly easy to require either malloc or operator new to
zero-initialize all storage it allocates. The question is, do we want
to do this all the time?

>This would be a difference in behaviour between C++ and C. I don't think
>it will cause problems, but perhaps someone with more experience will
>comment.
>
>What else am I missing? This is surely the kind of thing which future
>revisions of the C++ standard should be considering.

I don't think it is worth doing. Zero-initialization doesn't really
make sense for object type members, anyway. I think it's just part of
the job of programming to ensure that member variables are properly
initialized, and with properly designed classes, it's not such a big
chore. I's one of those things that make C++ different from, say,
Visual Basic <g>.

--
Bob Hairgrove
NoSpamPlease@Home.com

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pasa@lib.hu ("Balog Pal")
Date: Wed, 22 Sep 2004 17:07:53 GMT
Raw View
In an old version of this thread the idea I liked the most was having

int  item = __uninitialised;
int  item(__uninitialised);

To make some variable no initialised, and perform default-init for any place
there is no initialiser.

That makes ununited stuff explicit and easy to spot and search. Also it is
backward-compatible except for performance. And not so hard to fix later.

Reusing void or anything else is a bad idea. (If you really want to save a
keyword use static instead <EG>).

>(c) Zero-initialisation is not sufficient to satisfy the class invariant.

The invariant checks shall catch that.  The main problem with noinit is it
leads to UB and in practice to nondeterministic behavior. The memory-junk
may slip through tests if it happens to satisfy the invariant for the test
run.

>Zeros are cheaper when bought in bulk, especially if they can be produced
in idle time, and especially if the O/S makes them. So it would be nice if
we could make zero-initialisation the responsibility of the memory manager
rather than the class's constructor.

You forget C++-level zero-init is not a binary zero fill.  zero and null
vlaues may come with whatever bit patterns, and they in fact do for doubles.

Paul




---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: news0@nospam.demon.co.uk (John G Harris)
Date: Wed, 22 Sep 2004 17:14:58 GMT
Raw View
In message <memo.20040920104138.384A@brangdon.m>, Dave Harris
<brangdon@cix.co.uk> writes

  <snip>
>What else am I missing? This is surely the kind of thing which future
>revisions of the C++ standard should be considering.

1 Are there any compilers that make a good job of warning about the use
of uninitialised variables? If there are then surely that's a better
solution.

2 Why is zero a better junk value than any other junk value?

3 Wouldn't it be simpler to say that all stack space and all heap space
is zeroed before (re-)use?

4 What about volatile?

  John
--
John Harris

---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.jamesd.demon.co.uk/csc/faq.html                       ]