⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch11.htm

📁 c++语言操作手册
💻 HTM
📖 第 1 页 / 共 4 页
字号:
<!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>&lt;new&gt;</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 &lt;new&gt; // 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 &lt;cstdlib&gt;</tt><tt>#include &lt;string&gt;</tt><tt>using namespace std;</tt><tt>string* func() //very bad</tt><tt>{</tt><tt>  string *pstr = static_cast&lt;string*&gt; (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 &lt;cstdlib&gt;</tt><tt>using namespace std;</tt><tt>void func()</tt><tt>{</tt><tt>  int * p = static_cast&lt;int *&gt; 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 == &amp;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&lt;void *, std::size_t&gt;</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 + -