views:

612

answers:

5

Are uninitialized variables in Delphi guaranteed to have any particular value

  • on the stack?
  • on the heap?

Since C++Builder generally follows Delphi's design, are uninitialized variables in C++Builder guaranteed to have any particular value

  • on the stack?
  • on the heap, for member variables of classes derived from TObject?
  • on the heap, for member variables of POCOs?

I've inherited some C++Builder code that depends heavily in places on member variables being zero-initialized and am trying to figure out whether or not the language guarantees this.

Does Windows guarantee that memory is zero-initialized when it's first given to a program's stack or heap? (Edit: I realize that the program will overwrite memory as it executes and so it cannot continue to depend on this; I'm just trying to figure out the behavior that I've observed.)

+2  A: 

Short answer: in C++ you have to initialize everything

If C++Builder is anything like C++, then no there are no guarantees as to the contents of memory unless you explicitly initialize it.

While windows may blank pages before being made available to a program's stack or heap, unless you're requesting your own memory from the OS, you're probably using constructors or a library for memory allocation. Far more often you're getting a page or memory region you already used yourself. In that case it's pretty much guaranteed to be dirty. Doubly so for stack pages which are almost never new pages.

memset() would be how you wipe memory in C, but in C++ you need to provide default values for each field, or explicitly initialize them in the constructor.

caskey
I know that this is how C++ works, but C++Builder sometimes follows the Delphi model instead of the C++ model. I'm dealing with a large body of legacy code here, and if the language guarantees initialization, then there are higher priority tasks than initializing everything myself.
Josh Kelley
And in what case does C++Builder follow the Delphi model? C++ is C++. The only difference in zero-initialization is if you inherit from a Delphi class (like TForm). That is because the System::TObject::InitInstance() method fills the memory with zeros.
Andreas Hausladen
@Andreas: C++Builder follows the Delphi model when dealing with VCL style classes like TForm subclasses. See http://www.audacia-software.de/en/bcb/delphi-and-cpp-classes.htm (which would have answered my question, had I read it closely enough before posting).
Josh Kelley
Following "the Delphi model" is completely in line with C++. C++ doesn't forbid default initialization. It's undefined. Thus, any particular implementation (such as C++ Builder) is allowed to initialize variables and still be in compliance with the standard. Implementations are allowed to strengthen the "undefined" and "implementation-defined" portions of the standard to make them defined.
Rob Kennedy
@Rob: Good point, although C++Builder also follows the Delphi model in ways that aren't in line with C++ (order of constructors, exception handling details, etc.; see the link I gave for more details).
Josh Kelley
+1  A: 

In C++ memory is guaranteed to be initialised in the following circumstances:

  • for statically allocated variables
  • for an object with a constructor that initialises its members

In the first of these cases, POD data types like ints, pointers etc. will be zero initialised.

These are the only guarantees that the C++ Standard gives. Windows gives no guarantees at all in this area.

anon
+5  A: 

Since caskey's answer only concerns c++ my answer for delphi:

In delphi refer to this answer by Giacomo Degli Esposti

  • Object fields are always initialized to 0, 0.0, '', False, nil or whatever applies.
  • Global variables are always initialized. (to 0)
  • Local variables are unitialized so you have to assign a value before you can use them.

ms-help://borland.bds4/bds4ref/html/Variables.htm

All credits to Giacomo Degli Esposti

Edit: "Does Windows guarantee that memory is zero-initialized when it's first given to a program's stack or heap? "

Windows guarantees that memory is zero-initialized when it's first given to a new process (otherwise you'd have a big security issue with programs being able to read other processes discarded memory regardless of permissions). However using c++ this guarantee does not help you much as the c-runtime can overwrite the memory at its discretion before your code gets any chance to use it.

Edit2: For c++ builder variables are apparently initialized for "VCL-style classes" (whatever that means, all that inherit from TObject?), see http://docs.embarcadero.com/products/rad_studio/cbuilder6/EN/CB6_DevelopersGuide_EN.pdf

I quote:

"Because data members may be used in virtual functions, it is important to understand when and how they are initialized. In Object Pascal, all uninitialized data is zero-initialized. This applies, for example, to base classes whose constructors are not called with inherited. In standard C++, there is no guarantee of the value of uninitialized data members. The following types of class data members must be initialized in the initialization list of the class’s constructor: • References • Data members with no default constructor

Nevertheless, the value of these data members, or those initialized in the body of the constructor, is undefined when the base class constructors are called. In C++Builder, the memory for VCL-style classes is zero-initialized.

Technically, it is the memory of the VCL or CLX class that is zero, that is the bits are zero, the values are actually undefined. For example, a reference is zero.

A virtual function which relies upon the value of member variables initialized in the body of the constructor or in the initialization list may behave as if the variables were initialized to zero. This is because the base class constructor is called before the initialization list is processed or the constructor body is entered.

#include <sysutils.hpp>
class Base : public TObject {
public:
    __fastcall Base() { init(); }
     virtual void __fastcall init() { }
    };
class Derived : public Base {
    public:
     Derived(int nz) : not_zero(nz) { }
     virtual void __fastcall init()
     {
     if (not_zero == 0)
     throw Exception("not_zero is zero!");
     }
    private:
     int not_zero;
};
int main(void)
{
    Derived *d42 = new Derived(42);
    return 0;
}

This example throws an exception in the constructor of Base. Because Base is constructed before Derived, not_zero, has not yet been initialized with the value of 42 passed to the constructor. Be aware that you cannot initialize data members of your VCL-style class before its base class constructors are called."

Ben Schwehn
Shouldn't that be "discretion" rather than "disgression"?
dummzeuch
+1  A: 

In Delphi the TObject constructor zero-initializes the heap-allocated (always on the heap because TObjects cannot be stack-instantiated in Delphi) memory of the object thereby clearing all member variables.

Ville Krumlinde
A: 

On Delphi, as far as I know: * vcl classes auto initialize its fields. * Globals too

Local variables are not initialized. Their initial content is completely undefined. So, Assigned(variable) of TObject type will return false all times if the variable is local.

Fabricio Araujo