?? o32.htm
字號:
<html>
<head>
<title>關于指針和內存的幾個問題</title>
<meta http-equiv="目錄類型" content="文本/html; 字符集=gb2312">
<link rel="stylesheet" href="../bcbget.myric/o/Css.css" tppabs="http://bcbget.myrice.com/o/Css.css">
</head>
<body bgcolor="#FFFFFF">
<table width="100%" border="0" height="285">
<tr>
<td height="35">
<div align="center" class="p14"><font color="#000000">關于指針和內存的幾個問題</font></div>
</td>
</tr>
<tr valign="top">
<td>
<p>一、"delete p" 會刪去 "p" 指針,還是它指到的資料,"*p" ?
<p> 該指針指到的資料。"delete" 真正的意思是:「刪去指針指到的東西」(delete the thing
pointed to by)。同樣的英文誤用也發生在 C 語言的「釋放」指標所指向的記憶體("free(p)"真正的意思是:"free_the_stuff_pointed_to_by(p)"
)。
<p>二、能 "free()" 掉由 "new" 配置到的、"delete" 掉由
"malloc()"
配置到的記憶體嗎?
<p> 不行。在同一個程式里,使用 malloc/free 及 new/delete 是完全合法、合理、安全的;但 free
掉由 new 配置到的,或 delete 掉由 malloc 配置到的指標則是不合法、不合理的。 <br>
<p>三、為什麼該用 "new" 而不是 malloc() ?
<p> 建構子/解構子、型別安全性、可被覆蓋(overridability)。建構子/解構子:和 "malloc(sizeof(Fred))"
不同,"new Fred()" 還會去呼叫Fred 的建構子。同理,"delete p" 會去呼叫 "*p" 的解構子。 <br>
型別安全性:malloc() 會傳回一個不具型別安全的 "void*",而 "new Fred()"
則會傳回正確型態的指標(一個 "Fred*")。 <br>
可被覆蓋:"new" 是個可被物件類別覆蓋的運算子,而
"malloc" 不是以「各個類別」作為覆蓋的基準。
<p>四、為什麼 C++ 不替 "new" 及 "delete" 搭配個
"realloc()" ?
<p> 避免你產生意外。當 realloc() 要拷貝配置區時,它做的是「逐位元 bitwise」的拷貝,這會弄壞大
<br>
部份的 C++ 物件。不過 C++ 的物件應該可以自我拷貝才對:用它們自己的拷貝建構子或設定運算子。
<p>五、該怎樣配置/釋放陣列?
<p> 用 new[] 和 delete[] :
<p> Fred* p = new Fred[100]; <br>
//... <br>
delete [] p;
<p> 每當你在 "new" 運算式中用了 "[...]" 的話,你就 *!*必須*!* 在 "delete"
陳述中使用 "[]" 。這語法是必要的,因為「指向單一元素的指標」與「指向一個陣列的指標」在語法上并無法區分開來。
<p>六、萬一我忘了將 "[]" 用在 "delete" 由 "new
Fred[n]" 配置到的陣列,會發生什麼事?
<p> 災難。這是程式者的--而不是編譯器的--責任,去確保 new[] 與 delete[] 的正確配對。若你弄錯了,編譯器不會產生任何編譯期或執行期的錯誤訊息。堆積(heap)被破壞是最可能的結局,或是更糟的,你的程式會當掉。
<p>七、成員函數做 "delete this" 的動作是合法的(并且是好的)嗎?
<p> 只要你小心的話就沒事。所謂的「小心」是: <br>
1) 你得 100% 確定 "this" 是由 "new" 配置來的(而非 "new[]",亦非自訂的 "new"
版本,一定要是最原始的 "new")。 <br>
2) 你得 100% 確定該成員函數是此物件最後一個會去呼叫的。 <br>
3) 做完自殺的動作 ("delete this;") 後,你不能再去碰 "this" 的物件了,包括資料及運作行為在內。 <br>
4) 做完自殺的動作 ("delete this;") 後,你不能再去碰 "this" 指標了。換句話說,你不能查看它、將它與其他指標或是
NULL 相比較、印出其值、對它轉型、對它做任何事情。
<p> 很自然的,這項警告也適用於:當 "this" 是個指向基底類別的指標,而解構子不是virtual 的場合。
<p>八、該怎麼用 new 來配置多維陣列?
<p> 有很多方法,端視你對陣列大小的伸縮性之要求而定。極端一點的情形,如果你在編譯期就知道所有陣列的維度,你可以靜態地配置(就像
C 一樣):
<p> class Fred { /*...*/ };
<p> void manipulateArray() <br>
{ <br>
Fred matrix[10][20];
<p> //使用
matrix[i][j]...
<p> //不須特地去釋放該陣列 <br>
}
<p> 另一個極端情況,如果你希望該矩陣的每個小塊都能不一樣大,你可以在自由記憶體里配置之:
<p> void manipulateArray(unsigned
nrows, unsigned ncols[]) <br>
//'nrows' 是該陣列之列數。 <br>
//所以合法的列數為 (0, nrows-1) 開區間。
<br>
//'ncols[r]' 則是 'r' 列的行數 ('r'
值域為 [0..nrows-1])。 <br>
{ <br>
Fred** matrix =
new Fred*[nrows]; <br>
for (unsigned r
= 0; r < nrows; ++r) <br>
matrix[r]
= new Fred[ ncols[r] ];
<p> //使用
matrix[i][j]...
<p> //釋放就是配置的反動作:
<br>
for (r = nrows;
r > 0; --r) <br>
delete
[] matrix[r-1]; <br>
delete [] matrix;
<br>
}
<p>九、怎樣確保某類別的物件都是用 "new" 建立的,而非區域或整體/靜態變數?
<p> 確定該類別的建構子都是 "private:" 的,并定義個 "friend" 或 "static"
函數,來傳回一個指向由 "new" 建造出來的物件(把建構子設成 "protected:",如果你想要有衍生類別的話)。
<p> class Fred {
//只允許 Fred 動態配置出來 <br>
public: <br>
static Fred* create()
{ return new Fred(); } <br>
static Fred* create(int
i) {
return new Fred(i); } <br>
static Fred* create(const
Fred& fred) { return new Fred(fred); } <br>
private: <br>
Fred(); <br>
Fred(int i); <br>
Fred(const Fred&
fred); <br>
virtual ~Fred();
<br>
};
<p> main() <br>
{ <br>
Fred* p = Fred::create(5);
<br>
... <br>
delete p; <br>
} <br>
<br>
</p>
</td>
</tr>
</table>
<br>
</body>
</html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -