簡體   English   中英

C ++內存管理的引用類型

[英]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 ++會因為它有更嚴格的類型規則而抱怨)。
  • 您可以在指向不屬於數組的對象的指針中使用數組運算符(並且可能會崩潰)
  • 您可以對數組上的元素使用普通指針操作。
  • 您可以通過解釋該內存的較小連續部分來分配“大”內存塊和“創建自己的數組”,就像它們是較小對象數組的成員一樣(這正是您使用malloc()時獲得的內容)。

數組本身不是類型; 它們只是分配多個對象的便捷方式,也是一種在某些情況下更方便的指針方法。

我想到的唯一例外是“數組並不特殊”規則是通過new在C ++中分配的情況數組。 當你通過new分配一個數組時,它會留下信息(通常在數組附近的堆中,但這不是強制性的)關於數組在分配時包含多少元素。 然后,您必須使用特殊的delete []運算符來刪除該數組。 delete []查找並使用該額外信息來正確刪除數組的所有元素。

其次,我的主要問題是做c和c ++的內存管理機制(malloc,free和new,delete)總能正確處理這個並釋放類或數組所指向的內存嗎?

只要你做得對,是的。

如果這些指針以某種方式重新分配給堆上相同大小/類型的其他對象,那么一切仍然有效嗎?

是的free() ,雖然當你調用free()(除了void* )時使用指向不同類型的指針是一件相當不尋常的事情。 這些東西有合法用途,但它們是高級主題。 您可能希望由經驗豐富的開發人員查看您的設計,看看它是否真的適合做。

delete是另一回事; 如果您使用指向與調用delete時存儲在緩沖區中的類型不同的類型的指針,則行為是“未定義的”(也就是說您可能會崩潰)。 那是因為deletefree()更多; 它還調用對象的析構函數方法,編譯器依賴指針的類型來調用正確的方法。 如果使用錯誤的指針類型,將調用錯誤的方法,誰知道會發生什么。 你有可能把一些“其他”在緩沖區中的后, 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;
    }
}

當你刪除一條狗或者一只狗掉出范圍並被從堆疊中取出時,狗會被叫到。

引用基本上是一個使用自動變量語法的常量指針。 你不能改變它指向的東西,你不能用它來刪除一個對象(直接;你可以在引用上使用地址運算符來獲取指向被引用對象的指針,然后刪除它)。

函數mallocfree只分配和釋放內存塊。 您通常不需要在C ++中直接使用它們。 運算符newdelete分配並釋放內存,但它們也調用對象的構造函數和析構函數。 在類的構造函數中,所有自動成員的構造函數都被調用,並且與析構函數相同。 如果您的類具有指針成員,則不會自動分配或釋放其內存。 您必須在構造函數和析構函數中顯式執行此操作,或使用類似std :: auto_ptr的智能指針。

當在指針上使用delete運算符時,會調用指針類型的析構函數,因此如果強制指針指向錯誤類型並使用顯式轉換,則刪除它時將調用錯誤的析構函數。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM