C 棧物件 堆物件 理解

2021-06-23 07:18:22 字數 3106 閱讀 3515

在c++中,類的物件建立分為兩種,一種是靜態建立,如a a;另一種是動態建立,如a* ptr=new a;這兩種方式是有區別的。

1、靜態建立類物件:是由編譯器為物件在棧空間中分配記憶體,是通過直接移動棧頂指標,挪出適當的空間,然後在這片記憶體空間上呼叫建構函式形成乙個棧物件。使用這種方法,直接呼叫類的建構函式。

2、動態建立類物件,是使用new運算子將物件建立在堆空間中。這個過程分為兩步,第一步是執行operator new()函式,在堆空間中搜尋合適的記憶體並進行分配;第二步是呼叫建構函式構造物件,初始化這片記憶體空間。這種方法,間接呼叫類的建構函式。

第一種初始化方法:classname object(初始化引數);

第二種初始化方法:classname object=new classname();

兩種初始化方法的區別:

第一種初始化方法:在stack棧裡面分配空間,自動釋放。

第二種初始化方法:在heap堆裡面分配空間,要手動釋放。

什麼時候該用 object 

object

;什麼時候該用 object 

*object

;object

=new

object();

棧物件的優勢是在適當的時候自動生成,又在適當的時候自動銷毀,不需要程式設計師操心;而且棧物件的建立速度一般較堆物件快,因為分配堆物件時,會呼叫 

operator

new操作,

operator

new會採用某種記憶體空間搜尋演算法,而該搜尋過程可能是很費時間的,產生棧物件則沒有這麼麻煩,它僅僅需要移動棧頂指標就可以了。但是要注意的是,通常棧空間容量比較小,一般是1mb~2mb,所以體積比較大的物件不適合在棧中分配。特別要注意遞迴函式中最好不要使用棧物件,因為隨著遞迴呼叫深度的增加,所需的棧空間也會線性增加,當所需棧空間不夠時,便會導致棧溢位,這樣就會產生執行時錯誤。

堆物件,其產生時刻和銷毀時刻都要程式設計師精確定義,也就是說,程式設計師對堆物件的生命具有完全的控制權。我們常常需要這樣的物件,比如,我們需要建立乙個物件,能夠被多個函式所訪問,但是又不想使其成為全域性的,那麼這個時候建立乙個堆物件無疑是良好的選擇,然後在各個函式之間傳遞這個堆物件的指標,便可以實現對該物件的共享。另外,相比於棧空間,堆的容量要大得多。實際上,當物理記憶體不夠時,如果這時還需要生成新的堆物件,通常不會產生執行時錯誤,而是系統會使用虛擬記憶體來擴充套件實際的物理記憶體。

那麼如何限制類物件只能在堆或者棧上建立呢?下面分別進行討論。

1、只能在堆上分配類物件,就是不能靜態建立類物件,即不能直接呼叫類的建構函式。

容易想到將建構函式設為私有。在建構函式私有之後,無法在類外部呼叫建構函式來構造類物件,只能使用new運算子來建立物件。然而,前面已經說過,new運算子的執行過程分為兩步,c++提供new運算子的過載,其實是只允許過載operator new()函式,而operatornew()函式只用於分配記憶體,無法提供構造功能。因此,這種方法不可以。

當物件建立在棧上面時,是由編譯器分配記憶體空間的,呼叫建構函式來構造棧物件。當物件使用完後,編譯器會呼叫析構函式來釋放棧物件所佔的空間。編譯器管理了物件的整個生命週期。如果編譯器無法呼叫類的析構函式,情況會是怎樣的呢?比如,類的析構函式是私有的,編譯器無法呼叫析構函式來釋放記憶體。所以,

譯器在為類物件分配棧空間時,會先檢查類的析構函式的訪問性,其實不光是析構函式,只要是非靜態的函式,編譯器都會進行檢查。如果類的析構函式是私有的,則編譯器不會在棧空間上為類物件分配記憶體。因此,將析構函式設為私有,類物件就無法建立在棧上了。**如下:

class a

void destory()

private:

~a(){}

};

試著使用a a;來建立物件,編譯報錯,提示析構函式無法訪問。這樣就只能使用new操作符來建立物件,建構函式是公有的,可以直接呼叫。類中必須提供乙個destory函式,來進行記憶體空間的釋放。類物件使用完成後,必須呼叫destory函式。

上述方法的缺點:

一、無法解決繼承問題。如果a作為其它類的基類,則析構函式通常要設為virtual,然後在子類重寫,以實現多型。因此析構函式不能設為private。還好c++提供了第三種訪問控制,protected。將析構函式設為protected可以有效解決這個問題,類外無法訪問protected成員,子類則可以訪問。

二、類的使用很不方便,使用new建立物件,卻使用destory函式釋放物件,而不是使用delete。(使用delete會報錯,因為delete物件的指標,會呼叫物件的析構函式,而析構函式類外不可訪問)這種使用方式比較怪異。為了統一,可以將建構函式設為protected,然後提供乙個public的static函式來完成構造,這樣不使用new,而是使用乙個函式來構造,使用乙個函式來析構。**如下,類似於單例模式

class a

~a(){}

public:

static a* create()

void destory()

};

這樣,呼叫create()函式在堆上建立類a物件,呼叫destory()函式釋放記憶體。

2、只能在棧上分配類物件

只有使用new運算子,物件才會建立在堆上,因此,

只要禁用new運算子就可以實現類物件只能建立在棧上。

雖然你不能影響new operator的能力(因為那是c++語言內建的),但是你可以利用乙個事實:new operator 總是先呼叫 operator new,而後者我們是可以自行宣告重寫的。因此,

將operator new()設為私有即可禁止物件被new在堆上。**如下:

class a

// 注意函式的第乙個引數和返回值都是固定的

void operator delete(void* ptr){} // 過載了new就需要過載delete

public:

a(){}

~a(){}

};

C 棧物件,堆物件,靜態物件的理解

的優勢是在適當的時候自動生成,又在適當的時候自動銷毀,不需要程式設計師操心 而且棧物件的建立速度一般較堆物件快,因為分配堆物件時,會呼叫operator new操作,operator new會採用某種記憶體空間搜尋演算法,而該搜尋過程可能是很費時間的,產生棧物件則沒有這麼麻煩,它僅僅需要移動棧頂指標...

c 中堆物件與棧物件

使用棧物件的意外收穫 棧物件是在適當的時候建立,然後在適當的時候自動釋放的,也就是棧物件有自動管理功能。那麼棧物件會在什麼會自動釋放了?第一,在其生命期結束的時候 第二,在其所在的函式發生異常的時候。你也許說,這些都很正常啊,沒什麼大不了的。是的,沒什麼大不了的。但是只要我們再深入一點點,也許就有意...

棧物件和堆物件

在gameres上看見乙個問題帖 什麼時候該用 object object 什麼時候該用 object object object new object 感覺看起來沒什麼區別,其實不一樣 前乙個是棧物件,後乙個是堆物件。引用一下別人對棧物件 堆物件的解釋 棧物件的優勢是在適當的時候自動生成,又在適當...