- Overview
- Table of Contents
- Special Member Functions: Constructors, Destructors, and the Assignment Operator
- Operator Overloading
- Memory Management
- Automatic Storage
- Static Storage Duration and Thread Storage Duration
- Dynamic Storage Duration
- POD (Plain Old Data) and NonPOD Objects
- malloc() and free() Versus new and delete
- Support for Object Semantics
- Safety
- Allocating and Deallocating Arrays Using new[] and delete[]
- Dealing with Exceptions
- Placement new
- Allocating Arrays Using Placement new
- Member Alignment
- Overriding new and delete
- Linkage Types
- Guidelines for Effective Memory Management
- Summary
- Online Resources
- Replacing new and delete Operators, Part I
- Replacing new and delete Operators, Part II
- Pointers FAQ
- Pointers FAQ, Part II
- Pointers FAQ, Part III
- Pointers FAQ, Part IV
- Five Ways to Improve Your App's 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
- 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
Dynamic Storage Duration
Last updated Jul 2, 2009.
Objects created dynamically during program execution using new-expressions, and destroyed using delete-expressions have dynamic storage duration. Such objects reside on a memory section called free-store memory (also mistakenly called heap memory although the heap is a memory area designated for standard C memory management functions).
The lifetime of an object with dynamic storage duration begins once its initializer has completed. If an object has trivial initialization, its lifetime begins once storage with the proper alignment and size for the object is obtained. The lifetime of an object of type T ends when:
- If T is a class type with a non-trivial destructor, the destructor call starts.
- If T is class type with a trivial destructor, once the storage which the object occupies is reused or released.
Allocation and Deallocation Functions
Standard C++ provides the global allocation functions operator new and operator new[], and the global deallocation functions operator delete and operator delete[]. These functions should not be confused with the new operator and the delete operator which you normally use for creating objects dynamically and destroying them:
char *buf=operator new char[MAX];//operator new[] char * str=new char [MAX]; //new operator
The main difference between the allocation functions and the new operators is that the latter also initialize the allocated object. In other words, a new expression of the form:
string * pstr = new string;
Implicitly invokes the allocation function operator new[sizeof(std::string)], which returns an address of a raw memory buffer that has the proper alignment and size for type std::string. Next, the new operator invokes the constructor of class string, initializing the object *pstr. Similarly, the delete operator call:
delete pstr; //delete operator
First invokes the destructor of std::string and then calls the deallocation function operator delete[] to release the raw memory to the free-store.
Here's a simple way to remember the differences between allocation and deallocation functions on the one hand and the new and delete operators on the other hand. Operator new and operator delete deal with low-level raw memory management. They are the C++ equivalent of C's malloc() and free(), respectively. By contrast, the new operator and delete operator imply object semantics, meaning, initialization after the raw memory has been allocated, and destructor invocation before the raw memory is reclaimed, respectively.
Avoiding Resources Leaks
Objects and variables that are allocated on the free-store persist until they're explicitly released by a subsequent delete operator call. Failing to call delete results in a memory leak in the case of an object with a trivial destructor. Most modern operating systems will automatically reclaim such leaked memory once the program terminates but some embedded operating systems will not. Failing to call delete for an objects with a nontrivial destructor results in undefined behavior because the side-effects of the destructor will never take effect. Remember: releasing the raw storage of an object with dynamic storage duration is only one of a two-phased resource reclaiming procedure. The destructor of an object with dynamic storage duration must also be invoked in order to release additional resources that the object may own. Therefore, failing to call delete or delete[] to destroy a dynamically allocated object or an array of such objects is one of the most common and evasive bugs.
Unlike with objects with static storage duration, the address of an object with dynamic storage duration is determined at runtime. The initial value of the raw memory obtained from an operator new or operator new[] call is indeterminate. Some operating systems initialize the raw memory to binary zeros but it's best to not make any assumptions about it.
Scalar and Array Operators
C++ distinguishes between scalar new and delete, which allocate and deallocate a single object, and new[] and delete[], which allocate and deallocate arrays. For example:
int *p = new int; //scalar new char *s = new char[1024]; //array new, or new[] for short Shape *ps=new Triangle; std::string *pstr=new std::string delete p; //scalar delete delete[] s; //array delete, because s was allocated by new[] delete ps; //invokes the destructor, then releases raw memory delete pstr; //ditto
Never confuse the scalar operator with its array version or vice versa; the results in either case are undefined. Here's a simple guideline: if the pointer p was allocated using new[], you must use delete[] p to destroy it. If p was allocated using scalar new, use delete p:
int *p = new int; //scalar new delete p; //scalar delete std::string pstr = new string[10]; //new [] delete [] pstr; //delete[]



