- Overview
-
Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Templates
- Namespaces
- Time and Date Library
- Streams
- Object-Oriented Programming and Design Principles
- The Standard Template Library (STL) and Generic Programming
- Exception Handling
- Runtime Type Information (RTTI)
- Signal Processing
- Creating Persistent Objects
- Bit Fields
- New Cast Operators
- Environment Variables
- Variadic Functions
- Pointers to Functions
- Function Objects
- Pointers to Members
- Lock Files
- Design Patterns
- Dynamic Linking
-
Tips and Techniques
- Using the Swap() Algorithm
- Using class stopwatch for Performance Measurements
- Extending <tt><iostream></tt> to Support User-Defined Types
- Using <tt>auto_ptr</tt> To Automate Memory Management
- Using <tt>auto_ptr</tt> To Automate Memory Management, Part II
- Using <tt>auto_ptr</tt> To Automate Memory Management, Part III
- Using <tt>enum</tt>s as Mnemonic Indexes
- Create Objects on Pre-Allocated Memory Using <tt>Placement-new</tt>
- Online Books: <tt>Placement-new</tt>
- Bitwise Operators
- Bitwise Operators II
- Who's <tt>this</tt>?
- A Reference Guide
- The Virtues of Multiple Inheritance
- Interfaces
- Multiple Inheritance: Construction and Destruction Order
- nothrow new
- POD Initialization
- Object Initialization
- <tt>const</tt> Declarations
- The Semantics of <tt>volatile</tt>
- <tt>inline</tt> Functions
- Project Organization Guidelines
- All About <tt>bool</tt>
- <tt>typedef</tt> Declarations
- State of the <tt>union</tt>
- Dynamic Cast Uses
- Integrating C and C++
- <tt>const</tt>-Correctness
- <tt>const</tt>-Correctness: Advanced Issues
- Sprucing Up Legacy Code
- Virtual Constructors
- Naming Names
- Function Calls
- Speaking Standardese (updated)
- Speaking Standardese: the One Definition Rule
- Declarations and Definitions
- More on Declarations and Definitions
- The Most Vexing Parse
- Finally, At Last
- Sound Bytes (Admittedly Off Topic)
- Local Classes
- Complex Arithmetic
- Floating Point Woes
- String Manipulation
- The Object Model
- The Object Model II
- The Object Model III
- Temporary Objects
- Temporary Objects: Advanced Techniques
- Over-Engineering
- Security Enhancements
- Drop the (automatic) Pilot
- Choosing the Right Container
- Choosing the Right Container II
- Choosing the Right Container, Part III
- Arrays and Pointers
- Low-Level File I/O
- Low-Level File I/O Part II
- static Declarations, Part I
- static Declarations, Part II
- <code>static</code> Initialization Order
- Revisiting the Deprecation of File-Scope Static
- Virtual Memory and Memory Mapping
- Cellular Phone Programming Guidelines
- The Handle/Body Idiom
- Whole Program Optimization, Part I
- Whole Program Optimization, Part II
- Manipulating Directories
- Window Dressing
- <code>friend</code> Declarations
- <code>friend</code> Part II: the Interaction of Friendship and Template Classes
- Forcing Object Allocation on Specific Storage Types
- Lazy Evaluation
- Cache and Carry
- Controlling a Container’s Capacity
- Non-Blocking I/O, Part I
- Non-Blocking I/O, Part II
- Using Unions for Automatic Conversion
- Launching a Child Process
- <tt>switch</tt> Statements
- Introducing the "struct Hack"
- Scoped Enumerators
- Doing Statistics with STL
- Fixing the "Unresolved External" Linkage Error
- Understanding Calling Conventions
- Understanding the Empty Base Optimization
- Implementing RPC with the door Library, Part 1
- Implementing RPC with the door Library, Part 2
- Eliminating Two Common Pointer and <tt>sizeof</tt> Bugs
- Command Line Arguments
- Performance Myths Busting
- Tag Names And Types Part I
- Tag Names And Types Part II
- The Infamous goto
- Trimming Strings
- Can Objects Live Forever? Part I
- Can Objects Live Forever? Part II
- Five Ways to Improve Your Functions
- Member Aggregate Initialization
- Five Futile Coding-Style Debates
- The Good Parasite Idiom: An Exercise in OOD
- The Good Parasite Idiom: An Exercise in OOD, Part II
- The Good Parasite Idiom: An Exercise in OOD, Part III
- Ten Techniques to Reduce the Size of Your Classes, Part I
- Ten Techniques to Reduce the Size of Your Classes, Part II: Inheritance Issues
- Ten Techniques to Reduce the Size of Your Classes, Part III
- Ten Techniques to Reduce the Size of Your Classes IV
- Taking the Address of an Object with an Overloaded Operator <tt>&</tt>
- strcpy() -- How and Why Does It "Just Work"?
- Anonymous Structs
- Five Easy Ways to Reduce The Size of your Executables
- Standard Layout Classes and Trivially Copyable Types, Part I
- Standard Layout Classes and Trivially Copyable Types, Part II
- Five Simple Code Sanity Checks
- Five Things You Need to Know About C++11 Unions
- A Tour of C99
- A Tour of C1X
- C++0X: The New Face of Standard C++
- C++0x Concurrency
- The Reflecting Circle
- We Have Mail
- The Soapbox
- Numeric Types and Arithmetic
- Careers
- Locales and Internationalization
POD Initialization
Last updated Jan 1, 2003.
Unlike auto objects which are automatically initialized by their constructor, auto variables have an indeterminate (i.e., garbage) value by default. Explicit initialization of such variables eliminates unpleasant surprises at runtime and ensures that your code always behaves consistently. I will show how to explicitly initialize all sorts of automatic data: scalar types, pointers, arrays, structs and unions.
Built-in Types
Initialization of a built-in type (int, bool and double etc.) looks like an assignment expression: an assignment operator and an initializer appear after the variable's name. The only difference between plain assignment and an initialization is that the latter must appear in the variable's declaration. For example:
int func()
{
int val=100;
double price=99.99;
bool isopen=false;
Person *p=NULL;
//...
}
Each initializer is of the same type as the variable it initializes. As a special case, C++ allows you to use the literal 0 as a universal initializer</a> for all built-in types, including pointers, pointers to functions and pointers to members. Therefore, you may initialize isopen like this:
bool isopen=0; // 0 is converted to 'false'
Similarly, all pointer types may be initialized like this:
Person *p=0; //converted to NULL void (*pf)(int)=0; //pointer to function void (A::*pmf)(int)=0; //pointer to member function
In fact, C++ pundits advocate the use of 0 instead of NULL in pointer initializations as it will save you the trouble of #including a header file.
Arrays
As noted earlier, assignment and initialization look syntactically the same. Yet there are two major differences between the two. Conceptually, initializations are performed at compile time whereas assignments take place at runtime. More importantly, you may initialize an array or an aggregate (I will discuss aggregates shortly) but you can't assign to them:
char passenger[10]="Phileas"; //OK, initialization char passenger2[10]; passenger2 = "Fix"; //error: array assignment is illegal
If you provide fewer initializers than the number of elements that an array has, all remaining elements will be default-initialized. For example, in the following expression the array set has five elements but only the first three have explicit initializers:
int set[5]={0,1,2};
The elements set[4] and set[5] are implicitly initialized to 0 in this case. Therefore, if you wish to zero-initialize a large array, simply provide a single initializer and let the compiler take care of the rest:
double scores[500]={0.0}; //remaining 499 elements
//are initialized to 0.0 as well
The following declaration is equivalent because the literal 0 is implicitly converted to the type of the initialized object, i.e., 0.0:
double scores[500]={0};
Likewise, if you're using a char array:
char URL[2048]={0}; //all elements are initialized to '\0'
Notice how awkward and error prone a memset()-based "initialization" looks in comparison:
#include <cstring> char URL[2048]; memset(URL, 0, 2048);
Not only do you need to #include a special header but you also must specify the array's size. Worse yet, programmers might confuse between the second and third arguments:
int arr[100]; memset (arr, 100, 0); //bad! actually meant (arr, 0, 100)
To the programmer's surprise, arr's elements will contain garbage values at runtime.
Aggregates
An aggregate is a Plain Old Data(POD) struct, class or union, or an array of POD elements (as well as arrays of built-in types). To initialize a POD struct, provide one or more initializers in curly braces. If there are fewer initializers than the number of members, the remaining members are default-initialized:
struct employee
{
int age;
char [20] name;
char[100] address;
char occupation[50];
};
employee emp={45, "Passepartout", "Saville Row"};
The array occupation is zero-initialized since no explicit initializer was provided for it. You can easily zero initialize all the members of a struct like this:
employee e={0};
You're probably wondering whether this would work if the first member weren't a scalar type. For example,
struct Book
{
char[100] title;
char [100] author;
int pages;
};
Yes, it would:
Book b={0};
This works because aggregate initialization rules are recursive; the initializer 0 is initializes the first Book member, which is an array. As you already know, if an array's initialization list contains fewer initializers than the number of its elements, the remaining elements are zero-initialized. Thus, the literal 0 initializes the first element of the array title, letting the compiler zero-initialize all the remaining elements. Because b's initialization list doesn't provide explicit initializers for the members author and pages, they are all zero-initialized as well. Neat, isn't it?
Suppose we want to declare an array of Book objects. The same form of initialization will work here too:
Book arr[20] ={0};
Even if you change the definition of struct Book later (by adding more data members to it, for example) or if you change the size of the array b, the ={0}; initializer will properly initialize every element thereof.
Unions
Union initialization is similar to struct initialization except that it may include only a single initializer. This initializer must initialize the first union member. C++ guarantees that if the rest of the members are larger than the first, they're zero-initialized as well:
union U
{
int a;
char b[4];
};
U a = { 1 }; //fine
U b = a; //fine
U c = 1; // error
U d = { 0, "abc" }; // error
U e = { "abc" }; // error
Summary
Initializing auto variables is good programming practice. Of course, you don't have to initialize all variables to zero. However, you shouldn't leave auto varaibles uninitialized. A partial initialization list initializes the entire aggregate; members for which no explicit initializer is provided are default initialized. Unions are a special case -- only their first member can be initialized.
