views:

420

answers:

10

In one of the comments in this question, it was brought out that initializing C++ pointers by default would break compatibility with C.

That's fine, but why would something like this matter? I would think the only time it would actually matter is if I wanted an uninitialized pointer for some reason. But I can't think of a reason why I would want to have that.

Is there a use for uninitialized pointers? Or is the compatibility issue merely one of compatible behavior (i.e., not increasing overhead) and not one of breaking code?

+8  A: 

Initializing a pointer takes some time. Most of the time you shouldn't care about that, but there are rare occasions when it would make a difference. One of the guiding principles of C (and by extension C++) is never make you pay for something you might not need Don't pay for what you don't use.

Another rare case might come up in embedded programming, where a variable corresponds to a hardware register. Putting a value in the register will start the hardware performing some action which might be detremental.

Mark Ransom
Isn't it rather: "Don't pay for what you don't use."?
pmr
Makes me think of the old Fram Oil Filter commercial -- Pay me now, or pay me later. Back when I was doing commercial products in C we used our own memory allocator. In debug mode we would initialize all memory blocks to 0xa5a5a5a5. When something blew up you could immediately tell that something didn't get initialized.
Peter Rowell
@Peter: I've seen remember 0XDEADBEEF from back in the day for Amiga memory freed to kernel. MS VC++ debug uses 0xFD, 0XDD, 0XCC, and 0xCD for debug patterns as well.
Adisak
@Adisak, the compiler is free to initialize memory even if you don't do so explicitly. Usually this is reserved for "debug" builds. Some people have an issue with explicitly initializing pointers to nonsense values, but I think that's overreacting.
Mark Ransom
@Mark: Yep and this is exactly what VC++ does in debug builds for global, static, and local (stack) variables as well as patterning initially allocated memory. It does not however do any initialization of memory during constructors so you can do the in-place new over preformatted data hack. I just wrote a console memory system and I am adding a non-sense pattern initialization to it for debug purposes (it can be turned on/off easily)
Adisak
+1  A: 

Not having to pay for what you don't need is not here for compatibility with C. It's one of the most important principles of C++ too.

Samuel_xL
A: 

An uninitialized pointer is useful for one thing, and one thing only: Assigning something to it. The only reason you'd ever want one is that you don't have a fixed initial value, but plan on assigning one at some point in the future, and thus initializing it is a waste. You could assign it to NULL, if you wanted, or something else.

Since in C++ you can declare variables anywhere in a scope, and not just the start, this is no longer really relevant, since you could just declare it where you use it.

The short answer, though, is no. Just assign it to NULL.

McPherrinM
Assign 0 to it, you mean?
reinierpost
Unless, of course, you're OPENSSH, and are using it to generate a source of random data :-)
kdgregory
A: 

I'm not sure what comment you're talking about, but I think it only breaks syntactical compatibility. There's no use of uninitialized pointer, but there's also no use to initialize it before you know the value you want to put in there and we don't want to waste time on it.

Michael Krelin - hacker
The comment was Neil Butterworth's, on my answer.
John at CashCommons
If I understand it correctly, Neil's comment was about Robert's suggestion to Stroustrup. *That* would break compatibility.
Michael Krelin - hacker
Oh ok ... misunderstood the context, but apparently it's still an interesting question. ;)
John at CashCommons
And, I hope, you've got enough answers to choose from.
Michael Krelin - hacker
A: 

Suppose you have a function that is an interrupt handler that requires a lot of pointer stack variable(s):

void interruptHandler()
{
    char* ptr0;
    ...
    char* ptrX-1;
    char* ptrX;
}

Suppose its crucial you get in-and-out as fast as possible. You don't want to waste any needless time initializing to defaults, you know you'll try to be safe setting your pointersto something valid later.

Doug T.
This is actually much less of a big deal these days, because a modern optimising compiler would in most cases be able to prove to itself that the "initialised" value was always overwritten, and so safely omit it in the compiled form. (By the way, `ptrX-1` isn't a valid variable name ;)
caf
@caf, that's probably true unless your platform only has a c compiler written by "Joe's Compiler Shop" :)
Doug T.
Hey.. are you makin' fun of our compilers, or are you just unassuming?? Either way, 'dems fightin' words.
San Jacinto
+1  A: 

If you were to write a C style program in C++ but assumed pointers were initialized, then took that program back to a C compiler, it would fail to work. That's the only reason I could imagine it mattering.

Bill K
+2  A: 

It wouldn't break compatibility with C - a C implementation in which all unintialised pointers are actually initialised to 0 (or indeed, to anything at all!) would be perfectly conforming.

caf
+6  A: 

Use for an unitialised pointer? See std::strtol().

char * bad;
long n = std::strtol( "123xyz", &bad, 10 );

after this call, bad will contain a pointer to 'x'. There is no point in initialising it.

anon
+1, but then again it's exactly the case of initializing it later ;-)
Michael Krelin - hacker
char* bad; is probably the simplest example so far
0A0D
+13  A: 

This is a very specialized optimized case for Video Games (basically an embedded system). We used to use them for Load-In-Place data behavior in our Video Games to speed up loading (and avoid fragmentation).

Basically we would create console-side (Playstation) objects in a PC cooker. Then to reduce fragmentation overload, we would pack the data objects in a contiguous buffer with a single alloc. References to the data objects in this buffer would then be changed to subtract the base from pointers to offsets (unfix call -- we also had a virtual fix / unfix calls that took the buffer base and could convert between offsets and pointers).

When we loaded the data, it loaded in one large block. All data referenced by the root was off the root object. We could do an inplace "new" on the the root that would initialize the proper VF tables for the object and fixup all the attached blocks (by doing inplace new and then fixing up attached blocks respectively).

We needed the constructors called (in place new) to generate the proper VF-Tables in the objects. However, if the pointers were automatically cleared to NULL during the constructor, we would have lost the offset data and not been able to recreate the pointers between the objects within the contiguous block.


FWIW, this is a common technique in the Video Game world. This Gamasutra article (not written by me or my coworkers) explains in detail the similar thing they did at another company:

Also, this topic of discussion on SourceForge.

There have even been several GDC (Game Developer Conference) talks on the subject.

Searching on Google for "load-in-place" will give many other examples of people using this technique that basically requires uninitialized pointers.


NOTE: Currently, this is the only response that actually answers the question asked ("Is there a use for uninitialized pointers in C or C++?") by giving a specific use for pointers that must remain unitialized.

All the other responses are better answers for the original question referenced ("[C++] Why aren’t pointers initialized with NULL by default?") that caused the poster to ask this question.

Adisak
You do realize that what you've described is one huge non-portable, implementation-specific hack, right? In particular, there's no guarantee that any byte fiddling you may do in the memory in which you will then placement-new an object will reflect in any particular way in the values of the fields of that object. Not only that, but non-PODs (and you mention vtables, so those are non-PODs) have implementation-defined amount of extra data at start, and of course padding between field is also implementation-defined.
Pavel Minaev
Yes I do. We used it on very specific cases on PS and XBOX. The question asked if there were a reason to do something. We did it because it made loading our game take seconds instead of minutes (large single block load instead of many little objects created and loaded). It also saved a ton of memory and fragmentation. In the Video Game world (and embedded systems in general), these types of hacks are often necessary to hit performance and memory goals.
Adisak
note he said "embedded systems". it sounds to me like as far as optimization was concerned, it was justified free for all.
Matt Joiner
Yeah... this is the fun we had in the old days working on systems that had less total memory than current PC's have for L1 cache.
Adisak
If I could upvote this more than once, I would. Great story
0A0D
+10  A: 

First of all, initializing pointers (or any other variables) by default does not break compatibility with C. Both C and C++ state that a value of uninitialized variable is indeterminate; in practice, this means that it can hold any value (including a trap representation), but note that 0 belongs to the set of "any values"! So a conformant implementation can perfectly well initialize all pointers to 0. Your program, should it rely on that, would not be conformant, however.

Now as to why you may want your pointer to not be initialized: mainly when it is written to afterwards. For example:

void foo(int*& p) {
   p = new int;
}

int* p; // why initialize? we overwrite it anyway
foo(p);

You can say that compiler should be able to optimize this away. Unfortunately, it cannot do so if the definition of foo is not available (e.g. global link-time optimizations are disabled; or they are enabled, but the function is in a DLL), since it doesn't know if foo will try to read from p (and then initialization would be needed), or if it would just write to it (and then initialization isn't needed). What more, there may be cases that are harder to analyze; for example:

bool try_parse_int(const char* s, int& n)
{
    // if parsed successfully, assign result to n and return true
    // if there was error parsing, don't touch n and return false
    ...
}

int n;
if (try_parse_int(s, n)) {
    // use n here
    ...
} else {
   // don't use n here
   ...
}

This one is much harder for the compiler to analyze even if it has full definitions of all functions.

Pavel Minaev