<h4 class="docSection2Title">耗尽
内存</h4>
表达式就有可能失败。如果 <tt>new</tt> 表达式无法获取需要的内存空间,系统将抛出名为 <tt>bad_alloc</tt> 的
异常。我们将在<a class="docLink">第 6.13
节</a>介绍如何抛出异常。
<a name="ch05lev2sec20"></a>
<h4 class="docSection2Title">撤销动态创建的对象</h4>
<a name="idd1e38354"></a><a name="idd1e38357"></a><a name="idd1e38361"></a><a name="idd1e38367"></a><a name="idd1e38374"></a><a name="idd1e38379"></a><a name="idd1e38385"></a>
<p class="docText">动态创建的对象用完后,
程序员必须<span class="docEmp
hasis">显式</span>地将该对象占用的内存返回给自由存储区。C++ 提供了 <tt>delete</tt>
表达式释放指针所指向的地址空间。
delete pi;
</pre>
<p class="docText">frees the memory associated with the <tt>int</tt> object
addressed by <tt>pi</tt>.
<p class="docText">?
<a name="ch05note14"></a>
<div class="docNote">
<table border="0" cellspacing="0" cellpadding="1" width="90%"><tbody><tr>
<td width="60" valign="top"><br></td>
<td valign="top">
是不合法的。
</td>
</tr></tbody></table>
<a name="ch05term9"></a>
<p class="docText">C++ 没有明确定义如何释放指向不是用 <tt>new</tt> 分配的内存地址的指针。下面提供了一些安全的和不安全的
<span class="docEmphRoman"><a class="docLink">delete
expressions</a></span> 表达式。
int i;
int *pi = &i;
string str = "dwarves";
double *pd = new double(33);
delete str; // <span class="docEmphItalicAlt">error:</span> <span class="docEmphasis">str</span> <span class="docEmphItalicAlt">is not a dynamic object</span>
delete pi; // <span class="docEmphItalicAlt">error:</span> <span class="docEmphasis">pi</span> <span class="docEmphItalicAlt">refers to a local</span>
delete pd; // <span class="docEmphItalicAlt">ok</span>
</pre>
<p class="docText">?
语句。编译器知道
<tt>str</tt>
并不是一个指针,因此会在编译时就能检查出这个
错误。第二个错误则比较隐蔽:通常来说,编译器不能断定一个指针指向什么类型的对象,因此尽管这个语句是错误的,但在大部分编译器上仍能通过。
<a name="ch05lev2sec21"></a>
<h4 class="docSection2Title"><span style="font-family:
monospace;"><br></span></h4>
<h4 class="docSection2Title">零值指针的删除</h4>
<pre> int *ip = 0;
delete ip; // <span class="docEmphItalicAlt">ok: al
ways ok to delete a pointer that is equal to 0</span>
</pre>
<p class="docText">?
<h4 class="docSection2Title">在 <tt>delete</tt> 之后,重设指针的值</h4>
<p class="docText">?
<pre> delete p;
</pre>
<p class="docText"><span style="font-family: monospace;"><br></span>
没有定义,但仍然存放了它之前所指向对象的地址,然而 <tt>p</tt> 所指向的内存已经被释放,因此 <tt>p</tt> 不再有效。
<a name="ch05note15"></a>
<div class="docNote">
<table border="0" cellspacing="0" cellpadding="1" width="90%"><tbody><tr>
<td width="60" valign="top"><br></td>
<td valign="top">
<p class="docText">一旦删除了指针所指向的对象,立即将指针置为
0,这样就非常清楚地表明指针不再指向任何对象。
</td>
</tr></tbody></table>
<br>
<h4 class="docSection2Title">
<tt>const</tt> 对象的动态分配和回收</h4>
<p class="docText">C++ 允许动态创建 <tt>const</tt> 对象:
const int *pci = new const int(1024);
</pre>
<a name="ch05term14"></a>
<p class="docText">?
对象必须在创建时初始化,并且一经初始化,其值就不能再修改。上述
<span class="docEmphRoman"><a class="docLink">new 表达式</a></span>返回指向 <tt>int</tt> 型
<tt>const</tt> 对象的指针。与其他 <tt>const</tt> 对象的地址一样,由于 <tt>new</tt> 返回的地址上存放的是
<tt>const</tt> 对象,因此该地址只能赋给指向 <tt>const</tt> 的指针。
<pre> // <span class="docEmphItalicAlt">allocate default initialized</span> <span class="docEmphasis">const</span> <span class="docEmphItalicAlt">empty string</span>
const string *pcs = new const string;
</pre>
<p class="docText">?
所指向的对象初始化为空的 <tt>string</tt> 对象。内置类型对象或未提供默认
构造函数的类类型对象必须显式初始化。
<a name="ch05sb17"></a>
<table border="1" cellspacing="0" cellpadding="5" width="90%"><tbody><tr>
<td>
<h2 class="docSidebarTitle">警告:动态内存的管理容易出错</h2>
<p class="docText"><span class="docEmphStrong">下面三种常见的程序错误都与动态
内存分配相关:</span>
<div style="font-weight: bold;">
<ol class="docList" type="1">
<li>
<div style="font-weight: normal;">
)指向动态分配内存的指针失败,因而无法将该块内存返还给自由存储区。删除动态分配内存失败称为“内存泄漏(memory
leak)”。内存泄漏很难
发现,一般需等应用程序运行了一段时间后,耗尽了所有内存空间时,内存泄漏才会显露出来。
</li>
<li>
<div style="font-weight: normal;">
读写已删除的对象。如果删除指针所指向的对象之后,将指针置为 0
值,则比较容易检测出这类错误。
</li>
<li>
<div style="font-weight: normal;">
表达式。当两个指针指向同一个动态创建的对象,删除时就会发生错误。如果在其中一个指针上做 <tt>delete</tt>
运算,将该对象的内存空间返还给自由存储区,然后接着 <tt>delete</tt>
第二个指针,此时则自由存储区可能会被破坏。
</li>
</ol>
</td>
</tr></tbody></table>
<br><a name="ch05lev2sec24"></a>
<h4 class="docSection2Title">删除 <tt>const</tt> 对象</h4>
<a name="idd1e38708"></a><a name="idd1e38711"></a>
<p class="docText">?
对象的值,但可撤销对象本身。如同其他动态对象一样,
<tt>const</tt> 动态对象也是使用删除指针来释放的:
</pre>
<p class="docText">?
对象的指针,该语句同样有效地回收 <tt>pci</tt> 所指向的内容。