C 記憶體分配和拷貝建構函式寫研究

2021-09-07 02:29:35 字數 2818 閱讀 1072

昨晚參加筆試,開錯題,有印象中的概念,但目前尚不清楚是怎麼回事,什麼原理,導致錯誤的話題。現在總結。

一、c++寫記憶體分配研究

問題考察例如以下,請先不要看答案,看看你是否能做對,呵呵:

怎麼樣。暈了沒?正確答案及解析例如以下:

解析:char p = 「...」是乙個陣列。這個陣列是區域性變數。char *p = 「...」。是乙個指標,這個指標指向乙個字串常量。差別在於:陣列的話,字串是存在這個陣列裡的,由於這個陣列屬於區域性變數(存在棧區)。而當該函式執行完,位於棧區的區域性變數就銷毀了,就算把陣列的位址返回給主函式。主函式也無法訪問到原有字串了,應該輸出亂碼。可是,假設是指向字串常量的指標,這個字串是放在程式的常量區而不是放在區域性變數中,那麼把這個常量的位址返回給主函式,主函式也是能夠訪問它的。

以下就針對c++中的記憶體分配做個總結:

乙個c/c++編譯的程式占用的記憶體分為下面幾個部分:

1. 棧區(stack)

由編譯器自己主動分配釋放,存放函式位址、函式引數值、區域性變數的值等。

2. 堆區(heap)

就是那些由new分配的記憶體塊,他們的分配與釋放由程式猿負責。一般乙個new就要相應乙個delete。假設程式猿沒有釋放掉,那麼在程式結束後。作業系統會自己主動**。

3. 全域性/靜態區(static)

全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和初始化的靜態變數在一塊區域,為初始化的全域性變數和未初始化的靜態變數在相鄰的還有一塊區域。程式結束後由系統釋放。

4. 常量儲存區(const)

常量字串就是放在這裡的。

5. 程式**區

存放函式體的二進位制**。

當中。堆疊的主要差別例如以下:

爽歪歪了吧。以下就來看第二個問題吧。。

二、考察複製建構函式

問題描寫敘述例如以下。問該程式的三種情況:a 程式編譯錯誤。b 程式編譯成功。執行時出現錯誤。c 程式正常執行,輸出10。

答:a解析:改題考察了複製建構函式的相關知識,在《c++ primer》中解說了。複製建構函式的定義形式為:類名(const 類名 &變數名),即引數為類型別的引用。可是為什麼非要必須這樣定義呢?當然。const的意思很清楚,由於一般複製操作不希望改動實參中的值,因此我們用const來限定一下,當然這個const也能夠去掉。即:a(a &other)。我們來分析一下引用的必要性:

1. 防止死迴圈的遞迴呼叫

複製建構函式會在下面情況下呼叫:

1) 乙個物件以值傳遞的方式傳入函式體;

2) 乙個物件以值傳遞的方式從函式體返回。

3) 乙個物件須要通過另外乙個物件進行初始化。

因此,假設將複製建構函式定義為:a(a other),那麼當我們使用a b = a;時,實際上相當於將a作為實參傳遞給other,而這樣的情況下相當於1) 乙個物件以值傳遞的方式傳入函式體,又會觸發複製建構函式的呼叫,而在呼叫時又會觸發下一輪的複製建構函式的呼叫,關鍵的是採用這樣的方式呼叫過程無法結束,會陷入死迴圈。因此,複製建構函式的形參必須是引用型別。

2. 高效率的引用

引用比較高效,傳遞引用能夠避免複製(這也能夠用來解釋上乙個原因)。假設乙個資料物件相當的大。進行複製會浪費非常多時間,同一時候另一些型別是不支援複製的,像io類就是不能夠複製的。傳遞引用就能夠避免這些問題了。

通過以上的討論我們還能夠引出淺拷貝與深拷貝的問題。

對於普通型別的物件來說,它們之間的拷貝非常easy,比如:int a = 10 ; int b = a ;可是對於類型別的物件,在某些情況下就要考慮特殊的問題。

淺拷貝:淺拷貝就是物件成員之間的簡單賦值。比如,當你定義了乙個類而沒有提供它的複製建構函式,當時用該類的乙個物件去給還有乙個物件賦值時所執行的過程就是淺拷貝。

假設物件中沒有其他的資源(如:堆、檔案、系統資源等)。則深拷貝和淺拷貝沒有什麼差別,但當物件中有這些資源時,就必需要自己定義複製建構函式,來對這些物件進行合理的控制。

深拷貝:深拷貝指的是當拷貝物件中有其它資源(如堆、檔案、系統等)的引用時(引用能夠是指標或引用),物件得另開闢一塊新的資源。而不再對拷貝物件中有對其它資源的引用的指標或引用進行單純的賦值。如:

當我們通過例如以下使用它時:

int main()

b b = 10;

b c = b;

return 0;

假設未定義如上紅色標註的複製拷貝函式,則是淺拷貝。它只進行簡單的成員賦值。執行b c = b; 後c和b中的data都指向同一塊記憶體區。當b執行析構時,它的data所指的記憶體區就被釋放,而此時c的指標仍然指向那塊區域。利用data指標再訪問或c析構時都會發生記憶體洩露或程式崩潰。加上紅色標註部分即為深拷貝。在進行b c = b;時,c會又一次分配乙份空間,並將值拷貝過來。此時b析構完之後。c仍然能夠訪問。由於此時b和c指向的是兩塊不同的記憶體位址。

三、總結

通過上面的問題,發現自己對一些關鍵點理解的還是不夠透徹。都知道它要考察啥,但是大腦裡面知識結構太混亂,終於還是沒有得出正確答案。《c++ primer》然後,鞏固一下吧。油!

c 建構函式和拷貝建構函式

c 中為什麼要使用建構函式?c 是從c演變過來的,c中存在的是結構體,例如 對點point struct point 但是對點的操作還要在外部使用函式來實現。c 中包括了成員屬性和成員方法,但是由於類的封裝性,不能像普通變數乙個對成員屬性就行初始化,所以使用建構函式。class point doub...

C 建構函式和拷貝建構函式詳解

建構函式 析構函式與賦值函式是每個類最基本的函式。它們太普通以致讓人容易麻痺大意,其實這些貌似簡單的函式就象沒有頂蓋的下水道那樣危險。每個類只有乙個析構函式和乙個賦值函式,但可以有多個建構函式 包含乙個拷貝建構函式,其它的稱為普通建構函式 對於任意乙個類a,如果不想編寫上述函式,c 編譯器將自動為a...

C 的建構函式和拷貝建構函式

編譯器自動生成的構造僅僅做讓編譯能通過的事情,它不會初始化成員變數。編譯器並不會自動生成預設的建構函式和拷貝建構函式,僅僅在它需要的時候。沒錯!對於下面的類 class test 編譯器不會自動生成建構函式,因為沒有字段需要初始化。很多時候都需要深拷貝,這時需要自己定義copy constructo...