[英]C++ memory management of reference types
我仍然是一個相當新手的程序員,我對使用refence類型的c ++內存管理有疑問。
首先,我對參考類型的理解:
指針放在堆棧上,指針指向的實際數據被創建並放在堆上。 標准數組和用戶定義的類是refence類型。 它是否正確? 其次,我的主要問題是做c和c ++的內存管理機制(malloc,free和new,delete)總能正確處理這個並釋放類或數組所指向的內存嗎? 如果這些指針以某種方式重新分配給堆上相同大小/類型的其他對象,那么一切仍然有效嗎? 如果一個類有一個指向另一個對象的指針成員怎么辦? 我假設刪除/釋放類對象不釋放它的成員指針所指向的,這是正確的嗎?
謝謝大家!
-R
聽起來你正在從像C#這樣的托管語言接近C ++。 C ++中的情況有所不同。
您在C ++中不存在您描述為引用類型的內容。 C ++中的類型不是“引用類型”,也不是“值類型”。 他們只是'類型'。 它們是通過引用(或指針)還是通過值處理完全取決於使用類型的代碼(不是類型的定義 )。 相反,在像C#這樣的語言中,類型聲明器決定是否必須將類型作為引用或值處理。 C ++確實有一些稱為引用的東西,但它與你描述的東西無關。 我最后會提到C ++引用。
現在,讓我們看看我們是否可以處理您問題的幾個部分:
指針放在堆棧上,指針指向的實際數據被創建並放在堆上。
也許。 如果您創建這樣的對象,那將是真的,例如:
class MyClass { /* ... */ };
...
MyClass* pObj1 = new MyClass();
MyClass* pObj2 = (MyClass*)malloc( sizeof(MyClass) );
但是,如果您創建這樣的對象,那就不是:
MyClass obj3;
在后者中,對象在堆棧中分配,並且不涉及指針或引用。 您正在將其作為“值類型”進行操作。
MyClass *pObj3 = &obj3;
現在pObj3
是一個指針(在棧)到obj3
, 這也是在堆棧中 。 看到? 類定義與該類的對象存儲位置之間沒有任何關聯。 這取決於您如何使用該類型。 將相同類型的堆棧和基於堆的對象組合起來是很常見的。
標准數組和用戶定義的類是refence類型。 它是否正確?
沒有; 數組只是放置在連續內存位置的一組相同類型/大小的對象。 數組可以在堆棧中或堆中分配,就像使用單個對象一樣。
C和C ++沒有在數組上放置任何不同的語義(我將在一秒鍾內提到一個例外)。 一旦分配它們,它們就是一堆碰巧連續的對象。 您的程序可以使用數組操作或直接指針操作來訪問各個成員。 這意味着:
arrayOfClass[i]
與說((Class*)*(array + i))
完全相同 。 在C中,您甚至可以對i[arrayOfClass]
,它與arrayOfClass[i]
相同(但是C ++會因為它有更嚴格的類型規則而抱怨)。 數組本身不是類型; 它們只是分配多個對象的便捷方式,也是一種在某些情況下更方便的指針方法。
我想到的唯一例外是“數組並不特殊”規則是通過new
在C ++中分配的情況數組。 當你通過new
分配一個數組時,它會留下信息(通常在數組附近的堆中,但這不是強制性的)關於數組在分配時包含多少元素。 然后,您必須使用特殊的delete []
運算符來刪除該數組。 delete []
查找並使用該額外信息來正確刪除數組的所有元素。
其次,我的主要問題是做c和c ++的內存管理機制(malloc,free和new,delete)總能正確處理這個並釋放類或數組所指向的內存嗎?
只要你做得對,是的。
如果這些指針以某種方式重新分配給堆上相同大小/類型的其他對象,那么一切仍然有效嗎?
是的free()
,雖然當你調用free()(除了void*
)時使用指向不同類型的指針是一件相當不尋常的事情。 這些東西有合法用途,但它們是高級主題。 您可能希望由經驗豐富的開發人員查看您的設計,看看它是否真的適合做。
delete
是另一回事; 如果您使用指向與調用delete時存儲在緩沖區中的類型不同的類型的指針,則行為是“未定義的”(也就是說您可能會崩潰)。 那是因為delete
比free()
更多; 它還調用對象的析構函數方法,編譯器依賴指針的類型來調用正確的方法。 如果使用錯誤的指針類型,將調用錯誤的方法,誰知道會發生什么。 你有可能把一些“其他”在緩沖區中的后, new
倒是它,但可能需要工作的非平凡量,再次是一個高級主題。
另外請注意,你不應該與分配malloc()
和自由與delete
,也不應該你分配與new
和自由與free()
確保您的方法正確配對。
如果一個類有一個指向另一個對象的指針成員怎么辦? 我假設刪除/釋放類對象不釋放它的成員指針所指向的,這是正確的嗎?
在C ++中,處理它的規范方法是類應該有一個析構函數,而析構函數將負責釋放指針成員。 在C中你沒有選擇,你必須在清除外部指針之前手動清除指針成員。
這都假設對象擁有成員指針指向的內容。 在像C#這樣的托管語言中,所有對象都由運行時“擁有”並在垃圾回收器的控制下被刪除,因此您不必擔心它。 在C ++中。 成員指針指向的'擁有'對象的人是由程序的語義而不是語言定義的,你必須注意決定何時是刪除嵌入對象的正確時間。 如果您錯過了刪除對象的正確時間,則會泄漏內存; 如果你太快刪除它,你會得到未定義的行為和崩潰(當某些代碼試圖使用已被刪除的對象時)。
現在,C ++ 引用基本上只是一個帶有一點糖塗層的指針,旨在使某些指針更容易使用。 在priciple中,幾乎沒有什么可以通過使用指針在C ++中無法完成的引用; 少數例外是我將跳過的高級主題(我必須查看它以使主題公正,我手頭沒有我的資源)。
對於您的觀點,C ++引用只是一個看起來像堆棧對象的指針。
CMyClass pObj1 = new CMyClass();
CMyClass& myObject = pObj1; // Create a reference to the object pointed by pObj1
pObj1->Method1(); // Use the pointer to call Method1
pObj1.Method1(); // Use the reference to call Method1
鑒於你在C ++方面的知識水平,我現在可能遠離參考,直到你更好地理解C / C ++中的內存管理。
我假設刪除/釋放類對象不釋放它的成員指針所指向的,這是正確的嗎?
默認情況下這是正確的,這就是C ++類具有析構函數的原因。 例如:
class C {
int* x;
public:
C () : x (new int[10]) {} // constructor
};
C* cptr = new C; // a pointer to a C object
如果我刪除cptr
,則會釋放內存,因為x
未被釋放。 所以我將向C
添加一個析構函數:
class C {
...
~C () {delete [] x;} // destructor
};
(問題的其余部分存在很多問題。你似乎混淆了Java和C ++,這就是為什么你的大多數問題沒有意義。我只回答了這個片段給你一個如何自動免費資源。我建議你閱讀一本C ++書籍,以便更好地理解這門語言。)
我不知道從哪里開始。
我們有原始類型(例如int)。
我們的老朋友是c struct。
我們有課。
所有這些都可以自動存儲類; 只是坐在堆棧上。 所有都可以通過價值傳遞。
然后我們有指向x的指針。 ( x *
)。 它們將項目的地址存儲在堆棧中,或者分配到其他地方,就像new
。 一旦你得到一個指針,你應該確保你沒有做一些使它失效的事情。 如果從函數返回,則指向其動態上下文中的自動項的指針將變為無效。 如果使用delete
,則delete
的指針不再有效,當然也不是它的任何副本。
然后,最后,我們有參考。 x&只是語法糖。 傳遞對某事物的引用只是傳遞指向它的指針。 使用引用類型可以避免鍵入某些*
字符,並且斷言表下的指針永遠不會為空。
指針放在堆棧上,指針指向的實際數據被創建並放在堆上。
指針是變量,用於存儲另一個變量的地址。 是的, 可能就是這種情況。 指針始終指向本地作用域(或堆棧)或指向空閑存儲(堆)。
示例:
class Foo{
public:
// For Test1 This is in the Stack
// For Test2 this is in the free store
int x;
// For Test1 the pointer is in the Stack
// AND -> It points, to where we set it (could be stack or heap)
// For Test2 the pointer-variable-location is in the Free Store
// AND -> Similar
int *y;
}
int main()
{
// Lies in the Local Scope
Foo Test1;
// Test2 Lies in the Local Scope, and contains the address of the
// Object, which is now on the Free Store
Foo *Test2 = new Foo();
}
我的主要問題是做c和c ++的內存管理機制(malloc,free和new,delete)總能正確處理這個並釋放類或數組所指向的內存嗎?
首先,盡量避免混合和刪除。 其次, free()
獲取指針,不檢查指針提供的是否指向有效的內存位置。 這意味着您可以嘗試釋放可能導致Seg Faults的未分配內存。 一個標准的例子是
int main()
{
int * x; // Points to random
free(x); // Undefined behaviour
}
指針的另一個錯誤用法可能是:
int main()
{
int * x = malloc(sizeof(int) * 10); //Allocate an array of 10
++x; // Now points to x[1];
free(x); // Give me trouble
}
如果這些指針以某種方式重新分配給堆上相同大小/類型的其他對象,那么一切仍然有效嗎?
是的事情可以繼續工作,但這可能會導致內存韭菜。 只要你刪除舊的東西,這很好。
如果一個類有一個指向另一個對象的指針成員怎么辦? 我假設刪除/釋放類對象不釋放它的成員指針所指向的,這是正確的嗎?
free()
類不會調用析構函數,並且可以使用析構函數來避免內存泄漏。 使用delete
可以設置析構函數以刪除其他對象,否則會導致內存泄漏。
你的帖子告訴我你混淆了一些東西,你開始說C ++中的References但最后談論指針和free()
和delete
,並且通常給人的印象是你很困惑。 我想你應該得到一本好書。
類不一定是引用類型。 例如,如果您有以下代碼:
class dog {
int age;
char *name;
};
int main() {
int x;
dog barry;
...
}
然后在主內部,巴里和x將在堆棧上彼此相鄰。 所以堆棧將包含兩個整數和一個指向char的指針。
你是對的,說釋放對象不會釋放其成員指針所做的內存。 C ++不會為您執行任何自動內存管理,因此必須手動分配和釋放所有內容。 在這種情況下,最好給狗一個析構函數,比如
class dog {
~dog() {
delete name;
}
}
當你刪除一條狗或者一只狗掉出范圍並被從堆疊中取出時,狗會被叫到。
引用基本上是一個使用自動變量語法的常量指針。 你不能改變它指向的東西,你不能用它來刪除一個對象(直接;你可以在引用上使用地址運算符來獲取指向被引用對象的指針,然后刪除它)。
函數malloc
和free
只分配和釋放內存塊。 您通常不需要在C ++中直接使用它們。 運算符new
和delete
分配並釋放內存,但它們也調用對象的構造函數和析構函數。 在類的構造函數中,所有自動成員的構造函數都被調用,並且與析構函數相同。 如果您的類具有指針成員,則不會自動分配或釋放其內存。 您必須在構造函數和析構函數中顯式執行此操作,或使用類似std :: auto_ptr的智能指針。
當在指針上使用delete
運算符時,會調用指針類型的析構函數,因此如果強制指針指向錯誤類型並使用顯式轉換,則刪除它時將調用錯誤的析構函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.