📄 index.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<HTML>
<HEAD>
<META NAME="Author" Content="Steph Mineart">
<META HTTP-EQUIV="Content-Type" CONTENT="text/html;CHARSET=iso-8859-1">
<TITLE>ANSI/ISO C++ Professional Programmer's Handbook - Chapter 11 - Memmory Management</TITLE>
<link rel="stylesheet" TYPE="text/css" href="/includes/stylesheets/ebooks.css">
</head>
<BODY TEXT="#000000" BGCOLOR="#FFFFFF">
<CENTER>
<H1><img src="/publishers/que/series/professional/0789720221/button/que.gif" WIDTH="171" HEIGHT="66" ALIGN="BOTTOM" BORDER="0"><BR>
ANSI/ISO C++ Professional Programmer's Handbook</H1>
</CENTER>
<CENTER>
<P><A HREF="/publishers/que/series/professional/0789720221/index.htm"><img src="/publishers/que/series/professional/0789720221/button/contents.gif" WIDTH="128"
HEIGHT="28" ALIGN="BOTTOM" ALT="Contents" BORDER="0"></A>
<HR>
</CENTER>
<H1 align="center">11</H1>
<h1 align="center"> Memory Management</h1>
<address>by Danny Kalev</address>
<ul>
<li><a href="#Heading1">Introduction</a>
<li><a href="#Heading2">Types of Storage</a>
<ul>
<li><a href="#Heading3">Automatic Storage</a>
<li><a href="#Heading4">Static Storage</a>
<li><a href="#Heading5">Free Store</a>
</ul>
<li><a href="#Heading6">POD (Plain Old Data) and non-POD Objects</a>
<li><a href="#Heading7">The Lifetime of a POD Object</a>
<li><a href="#Heading8">The Lifetime of a non-POD Object</a>
<li><a href="#Heading9">Allocation and Deallocation Functions</a>
<ul>
<li><a href="#Heading10">Semantics of Allocation Functions</a>
<li><a href="#Heading11">Semantics of Deallocation Functions</a>
</ul>
<li><a href="#Heading12">malloc() and free() Versus new and delete</a>
<ul>
<li><a href="#Heading13">Support For Object Semantics</a>
<li><a href="#Heading14">Safety</a>
<li><a href="#Heading15">Extensibility</a>
</ul>
<li><a href="#Heading16">new and delete</a>
<ul>
<li><a href="#Heading17">Allocating and Deallocating Arrays Using new[]
and delete[]</a>
<li><a href="#Heading18">Exceptions and Operator new</a>
<li><a href="#Heading19">Exception-Free Version of Operator new</a>
<li><a href="#Heading20">Placement new</a>
</ul>
<li><a href="#Heading21">Exceptions During Object Construction</a>
<li><a href="#Heading22">Alignment Considerations</a>
<ul>
<li><a href="#Heading23">Member Alignment</a>
</ul>
<li><a href="#Heading24">The Size Of A Complete Object Can Never Be Zero</a>
<li><a href="#Heading25">User-Defined Versions of new and delete Cannot Be Declared
in a Namespace</a>
<li><a href="#Heading26">Overloading new and delete in a Class</a>
<li><a href="#Heading27">Guidelines for Effective Memory Usage</a>
<ul>
<li><a href="#Heading28">Prefer Automatic Storage to Free Store Whenever
Possible</a>
<li><a href="#Heading29">Correct Syntax for Local Object Instantiation</a>
<li><a href="#Heading30">Zero As A Universal Initializer</a>
<li><a href="#Heading31">Always Initialize Pointers</a>
</ul>
<li><a href="#Heading32">Explicit Initializations of POD Object</a>
<ul>
<li><a href="#Heading33">Initializing Local Automatic Structs and Arrays</a>
<li><a href="#Heading34">Union Initialization</a>
<li><a href="#Heading35">Detecting a Machine's Endian</a>
<li><a href="#Heading36">The Lifetime Of A Bound Temporary Object</a>
<li><a href="#Heading37">Deleting A Pointer More Than Once</a>
</ul>
<li><a href="#Heading38">Data Pointers Versus Function Pointers</a>
<li><a href="#Heading39">Pointer Equality</a>
<li><a href="#Heading40">Storage Reallocation</a>
<li><a href="#Heading41">Local Static Variables</a>
<li><a href="#Heading42">Global Anonymous Unions</a>
<li><a href="#Heading43">The const and volatile Properties of an Object</a>
<li><a href="#Heading44">Conclusions</a>
</ul>
<hr size=4>
<h2> <a name="Heading1"> Introduction</a></h2>
<p>C++ added the necessary language constructs to the memory model of C to support
object semantics. In addition, it fixed some loopholes in the original model
and enhanced it with higher levels of abstraction and automation. This chapter
delves into the memory model of C++, starting with the three types of data storage.
Next, the various versions of operators <tt>new</tt> and <tt>delete</tt> are
discussed; finally, some techniques and guidelines for effective and bug-free
usage of the memory management constructs are presented.</p>
<h2> <a name="Heading2"> Types of Storage</a></h2>
<p>C++ has three fundamental types of data storage: automatic storage, static
storage, and free store. Each of these memory types has different semantics
of object initialization and lifetime.</p>
<h3> <a name="Heading3"> Automatic Storage</a></h3>
<p>Local objects that are not explicitly declared <tt>static</tt> or <tt>extern</tt>,
local objects that are declared <tt>auto</tt> or <tt>register</tt>, and function
arguments have <i>automatic storage</i>. This type of storage is also called
<i>stack memory</i>. Automatic objects are created automatically upon entering
a function or a block. They are destroyed when the function or block exits.
Thus, on each entry into a function or a block, a new copy of its automatic
objects is created. The default value of automatic variables and nonclass objects
is indeterminate.</p>
<h3> <a name="Heading4"> Static Storage</a></h3>
<p>Global objects, static data members of a class, namespace variables, and static
variables in functions reside in static memory.</p>
<p> The address of a static object remains the same throughout the program's execution.
</p>
<p>Every static object is constructed only once during the lifetime of the program.
By default, static data are initialized to binary zeros. Static objects with
a <i>nontrivial constructor</i> (see Chapter 4, "Special Member Functions: Default
Constructor, Copy Constructor, Destructor, And Assignment Operator") are subsequently
initialized by their constructors. Objects with static storage are included
in the following examples:</p>
<pre>
<tt>int num; //global variables have static storage</tt>
<tt>int func()</tt>
<tt>{</tt>
<tt> static int calls; //initialized to 0 by default</tt>
<tt> return ++calls;</tt>
<tt>}</tt>
<tt>class C</tt>
<tt>{</tt>
<tt>private:</tt>
<tt> static bool b;</tt>
<tt>};</tt>
<tt>namespace NS</tt>
<tt>{</tt>
<tt> std::string str; //str has static storage </tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading5"> Free Store</a></h3>
<p>Free store memory, also called <i>heap memory</i> or <i>dynamic memory</i>,
contains objects and variables that are created by operator <tt>new</tt>. Objects
and variables that are allocated on the free store persist until they are explicitly
released by a subsequent call to operator <tt>delete</tt>. The memory that is
allocated from the free store is not returned to the operating system automatically
after the program's termination. </p>
<p>Therefore, failing to release memory that was allocated using <tt>new</tt>
generally yields memory leaks. The address of an object that is allocated on
the free store is determined at runtime. The initial value of raw storage that
is allocated by <tt>new</tt> is unspecified.</p>
<h2> <a name="Heading6"> POD (Plain Old Data) and non-POD Objects</a></h2>
<p>A <i>POD</i> (<i>plain old data</i>) object has one of the following data types:
a fundamental type, pointer, union, struct, array, or class with a trivial constructor.
Conversely, a non-POD object is one for which a nontrivial constructor exists.
The properties of an object are in effect only during its <i>lifetime</i>.</p>
<h2> <a name="Heading7"> The Lifetime of a POD Object</a></h2>
<p>A POD object begins its lifetime when it obtains storage with the proper alignment
and size for its type, and its lifetime ends when the storage for the object
is either reused or deallocated. </p>
<h2> <a name="Heading8"> The Lifetime of a non-POD Object</a></h2>
<p>A non-POD object begins its lifetime after the constructor call has completed;
its lifetime ends when its destructor has started. </p>
<h2> <a name="Heading9"> Allocation and Deallocation Functions</a></h2>
<p>C++ defines the global <i>allocation functions</i> <tt>new</tt> and <tt>new[]</tt>
as well as the corresponding global <i>deallocation functions</i> <tt>delete</tt>
and <tt>delete[]</tt>. These functions are accessible from each translation
unit of a program without including the header <tt><new></tt>. Their implicit
declarations are as follows:</p>
<pre>
<tt>void* operator new(std::size_t) throw(std::bad_alloc); // new</tt>
<tt>void* operator new[](std::size_t) throw(std::bad_alloc); // new []</tt>
<tt>void operator delete(void*) throw(); // delete</tt>
<tt>void operator delete[](void*) throw(); // delete[]</tt>
</pre>
<p>The implicit declarations introduce only the function names operator <tt>new</tt>,
operator <tt>new[]</tt>, operator <tt>delete</tt>, and operator <tt>delete[]</tt>.
However, they do not introduce the names <tt>std</tt>, <tt>std::bad_alloc</tt>,
and <tt>std::size_t</tt>. An explicit reference to any of these names requires
that the appropriate header file be included. For example</p>
<pre>
<tt>#include <new> // declarations of std and size_t</tt>
<tt>using namespace std;</tt>
<tt>char * allocate (size_t bytes);</tt>
<tt>int main</tt>
<tt>{</tt>
<tt> char * buff = allocate(sizeof (char) );</tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading10"> Semantics of Allocation Functions</a></h3>
<p>The return type of an allocation function is <tt>void *</tt>, and its first
parameter is of type <tt>size_t</tt>. The value of the first parameter is interpreted
as the requested memory size. The allocation function attempts to allocate the
requested size of memory from the free store. If the allocation request is successful,
it returns the address of the start of a block of storage whose size, in bytes,
is at least as large as the requested size.</p>
<h3> <a name="Heading11"> Semantics of Deallocation Functions</a></h3>
<p>The return type of a deallocation function is <tt>void</tt>; its first parameter
is of type <tt>void *</tt>. A deallocation function can have more than one parameter.
The value of the first argument that is supplied to a deallocation function
can be <tt>NULL</tt> (in this case, the deallocation function call has no effect).
Otherwise, the value supplied to a deallocation function must be one of the
values returned by a previous invocation of a corresponding allocation function.Allocation
and deallocation functions perform the basic operations of allocating memory
from the free store and releasing it. Note however, that in general, you do
not invoke these functions directly. Rather, you use a <i>new expression</i>
and a <i>delete expression</i>. A new expression implicitly invokes an allocation
function and then constructs an object on the allocated memory; likewise, a
delete expression destroys an object, and then it invokes a deallocation function
to release the storage of the destroyed object.</p>
<blockquote>
<hr>
<strong>NOTE: </strong> In the following sections, <tt>new</tt> and <tt>delete</tt>
refer to a <tt>new</tt> expression and a <tt>delete</tt> expression, respectively,
unless stated otherwise.
<hr>
</blockquote>
<h2> <a name="Heading12"> malloc() and free() Versus new and delete</a></h2>
<p>C++ still supports the standard C library functions <tt>malloc()</tt> and <tt>free()</tt>.
The backward compatibility with C is useful in three cases: for combining legacy
code that was originally written in C in C++ programs, for writing C++ code
that is meant to be supported in C environment (more on this in Chapter 13,
"C Language Compatibility Issues"), and for making <tt>new</tt> and <tt>delete</tt>
implementable by calling <tt>malloc()</tt> and <tt>free()</tt>.</p>
<p>Otherwise, <tt>malloc()</tt> and <tt>free()</tt> are not to be used in C++
code because -- unlike <tt>new</tt> and <tt>delete</tt> -- they do not support
object semantics. <tt>new</tt> and <tt>delete</tt> are also significantly safer
and more extensible.</p>
<h3> <a name="Heading13"> Support For Object Semantics</a></h3>
<p><tt>new</tt> and <tt>delete</tt> automatically construct and destroy objects.
<tt>malloc()</tt> and <tt>free()</tt>, on the other hand, merely allocate and
deallocate raw memory from the heap. In particular, using <tt>malloc()</tt>
to create a non-POD object yields undefined behavior. For example</p>
<pre>
<tt>#include <cstdlib></tt>
<tt>#include <string></tt>
<tt>using namespace std;</tt>
<tt>string* func() //very bad</tt>
<tt>{</tt>
<tt> string *pstr = static_cast<string*> (malloc (sizeof(string))); //disaster!</tt>
<tt> return pstr; //any attempt to use pstr as a pointer to a string is undefined</tt>
<tt>}</tt>
</pre>
<h3> <a name="Heading14"> Safety</a></h3>
<p>Operator <tt>new</tt> automatically calculates the size of the object that
it constructs. Conversely, with <tt>malloc()</tt>, the programmer has to specify
explicitly the number of bytes that have to be allocated. In addition, <tt>malloc()</tt>
returns a pointer to <tt>void</tt>, which has to be explicitly cast to the desired
type. This is both tedious and dangerous. Operator <tt>new</tt> returns a pointer
to the desired type, so no explicit type cast is required. For example</p>
<pre>
<tt>#include <cstdlib></tt>
<tt>using namespace std;</tt>
<tt>void func()</tt>
<tt>{</tt>
<tt> int * p = static_cast<int *> malloc(sizeof(int));</tt>
<tt> int * p2 = new int;</tt>
<tt>}</tt>
<tt> </tt>
</pre>
<h3> <a name="Heading15"> Extensibility</a></h3>
<p>Operator <tt>new</tt> can be overloaded by a class. This feature enables specific
classes to use different memory management policies, as you will see next. On
the other hand, <tt>malloc()</tt> cannot be overloaded for a specific class.</p>
<p>The results of calling <tt>free()</tt> to release a pointer that was allocated
by <tt>new</tt>, or of using <tt>delete</tt> to release memory that was allocated
by <tt>malloc()</tt>, are undefined. The Standard does not guarantee that the
underlying implementation of operator <tt>new</tt> uses <tt>malloc()</tt>; furthermore,
on some implementations <tt>malloc()</tt> and <tt>new</tt> use different heaps.</p>
<h2> <a name="Heading16"> new and delete</a></h2>
<h3> <a name="Heading17"> Allocating and Deallocating Arrays Using new[] and delete[]</a></h3>
<p><tt>new[]</tt> allocates an array of objects of the specified type. The value
that is returned by <tt>new[]</tt> is the address of the first element in the
allocated array. For example</p>
<pre>
<tt>int main()</tt>
<tt>{</tt>
<tt> int *p = new int[10];</tt>
<tt> bool equal = (p == &p[0]); //true</tt>
<tt> delete[] p;</tt>
<tt> return 0;</tt>
<tt>}</tt>
</pre>
<p>Objects that are allocated using <tt>new[]</tt> must be released by a call
to <tt>delete[]</tt>. Using plain <tt>delete</tt> instead of <tt>delete[]</tt>
in this case results in undefined behavior. This is because when <tt>new[]</tt>
is executed, the runtime system stores the number of elements in the allocated
array in an implementation-defined way. The corresponding <tt>delete[]</tt>
expression retrieves the number of allocated elements to invoke the same number
of destructors. How does <tt>new[]</tt> store the number of elements in the
allocated array? The most widely used technique is to allocate an extra <tt>sizeof(std::size_t)</tt>
bytes; that is, for a class <tt>C</tt>, the expression</p>
<pre>
<tt>C * p = new C[n];</tt>
</pre>
<p>allocates a memory buffer that contains <tt>sizeof(std::size_t) + n * sizeof
</tt> bytes. The value <tt>n</tt> is written to the allocated buffer just before
the first <tt>C</tt> object. When <tt>delete[]</tt> is invoked, it looks for
the value <tt>n</tt> in a fixed offset before <tt>p</tt> (which must point to
the first element in the array). <tt>delete[]</tt> then invokes <tt>C</tt>'s
destructor <tt>n</tt> times and, finally, releases the memory block. Plain <tt>delete</tt>,
on the other hand, does not perform such offset adjustments -- it simply invokes
the destructor of the object to which <tt>p</tt> points.</p>
<p>An alternative technique is to store <tt>n</tt> in an associative array in
which <tt>p</tt> serves as the key and <tt>n</tt> is its associated value. When
the statement</p>
<pre>
<tt>delete[] p;</tt>
</pre>
<p>is executed, <tt>delete[]</tt> can lookup <tt>p</tt> in an associative array
such as</p>
<pre>
<tt>std::map<void *, std::size_t></tt>
</pre>
<p>and retrieve its associated value <tt>n</tt>. Other techniques for storing
the number of array elements can be used as well, but in any one of them, using
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -