《c++ primer》讀書筆記12

距離本筆記的上一篇已經過了很長時間了,很多人問我爲什麼不寫了,其實理由很簡單,我寫不出什麼東西,正如上篇筆記所說的在這之前的東西只是爲了向朋友們推薦一本好書以及幫助初學者熟悉作者的思考習慣,這個很容易,但也很膚淺,這樣的東西是不合適寫的太多的(地球人都知道的東西,還是看書爲好)。這就意味着必須選擇話題來寫(當然也大大增加了筆者犯錯的機會)。上面這些話算是對一直支持我的朋友們做個解釋,也希望再得到你們的支持。<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

 

在本篇文字中,我選擇的話題是指針,是的,我已經聽到很多人開始抱怨這個麻煩的該死的東西,但是我不得不說離開了這個東西(那個麻煩的該死的)你很難幹得成什麼事情,對於c/c++程序員來說這是個不可能迴避的問題,那麼我們最好還是看看這個東西到底麻煩在那兒,這樣比抱怨更能解決問題。

第一,      指針的定義和初始化:在本書的3.3節在這方面作了詳細的描述,很簡單,指針是一種間接操作對象的方式,指針中存放的是所操作對象在內存中的地址,但請注意,如果指針表示的僅僅是地址的話,事情就好辦得多,但是指針還必須與他表示的對象的類型保持一致,就象本書p73的例子:
int *p = NULL;”
double dval = 3.14;
p = &dval;  // error
不是p物理上不能存放dval的地址,而是兩種類型的內存佈局和內容的解釋完全不同(對編譯器而言),編譯器只好從一開始就拒絕這種賦值形式,當然,從你開始看上面的代碼的那一刻,我就知道你不以爲然了,一個學過編程的人是不會犯這種低級錯誤的,真的是這樣嗎?那麼好,我想有時候你會希望對指針直接賦個地址,你是否會這樣寫?
  int *p = 0x00001010;
然後,編譯器就開始罵人了,“0x00001010是那個對象的地址?什麼類型?一定是int嗎?你讓我咋解釋他呢?重寫!”呵呵,也難怪他脾氣這麼大,你這個地址根本就沒有告訴編譯器類型信息嘛,當然如果你非要這樣做,要麼告訴他你需要這個地址的類型:
  int *p = (int*)0x00001010;
要麼乾脆先不管類型的事情:”
  void *p = 0x00001010;
但不管你選那個方式,cast總是免不了,建議少用。

 

第二,野指針:當指針賦值的時候,編譯器會檢查地址的類型信息,這很好,但賦值之後他就不管了,這個正是一切麻煩的根源,比如有個典型的代碼:
#include <iostream>

#include <cstdlib>

using namespace std;

int*f()

{

    int a = 0;

    return &a;

}

int g()

{

    double a;

    cin >> a;

    return 0;

}   

int main()

{    

      

       int *p = f();

       cout << *p << endl;

       g();

       cout << *p << endl;

       system("pause");

       return 0;

}

 

我們發現編譯器沒有報錯,而p中存放的地址也沒被改變,但兩次提領的結果完全不同,這是因爲一旦函數f結束後,局部對象a進入了棧粉碎機,但是,請注意,棧粉碎機除去的不是該對象的地址編號和數據。而是該對象地址的類型標誌(當然這是編譯器行爲,和純內存無關)。而指針則仍然按照之前的約定對該對象地址進行提領等操作,一旦該對象地址被改變了類型信息,就必然錯誤。一個指針指向的對象的類型信息被改變者被消除,從而使得指針操作的結果不可預測,就成爲野指針。

第三,內存泄漏:這個問題跟堆上分配有直接的關係,首先,我們要明白什麼是內存泄漏,下面這個函數f內存泄漏了嗎?
int*f()

{

    int *p = new(int);

    return p;

}

int main()

{    

      

       int *p = f();

       *p = 11;

       cout << *p << endl;

       system("pause");

       delete p;

       return 0;

}

我們還是引用《effective c++》裏的一段話來回答這個問題:
引起內存泄露的原因在於內存分配後指向內存的指針丟失了。如果沒有垃圾處理或其他語言之外的機制,這些內存就不會被收回

顯然我們沒有丟掉控制該地址的指針,被分配的內存仍掌握在我們手裏。只不過要相當注意罷了。特別是當有異常出現的時候,不要忘記在程序退出之前delete這個內存。(當然有時候auto_ptr也是個不錯的選擇)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章