簡體   English   中英

何時在C ++中從內存中刪除變量?

[英]When are variables removed from memory in C++?

我現在一直在使用C ++。 我只是不確定內存管理是如何工作的,所以在這里:

我首先不確定函數中的內存是如何分配的,例如:

int addTwo(int num)
{
    int temp = 2;
    num += temp;
    return num;
}

那么在這個例子中,函數結束后是否會從內存中刪除? 如果沒有,這是怎么做的。 在C#中,一旦變量用完,變量就會被刪除。 還有其他我應該知道的案例嗎?

謝謝

在C ++中有一個非常簡單的經驗法則:

除非已手動分配,否則當超出范圍時,將自動釋放所有內存。

手動分配:

  • new()分配的任何對象必須由匹配的delete()取消分配。
  • malloc()分配的任何內存必須由匹配的free()解除分配。

C ++中一個非常有用的設計模式稱為RAII資源獲取是初始化 ),它將動態分配綁定到一個作用域對象,從而釋放其析構函數中的分配。

在RAII代碼中,您不必再擔心調用delete()或free(),因為只要“錨點對象”超出范圍,就會自動調用它們。

這里, temp被分配在堆棧上,當函數退出時,它自動釋放它使用的內存。 但是,您可以在堆上分配它,如下所示:

int *temp = new int(2);

要解放它,你必須這樣做

delete temp;

如果在堆棧上分配變量,通常會發生這種情況:

當你調用你的函數時,它會增加這個稱為“堆棧指針”的東西 - 一個數字,說明內存中的哪些地址被“保護”以供其局部變量使用。 當函數返回時,它會將堆棧指針遞減到其原始值。 實際上沒有對你在該函數中分配的變量進行任何操作,除了它們所在的內存不再受“保護” - 其他任何東西都可以(並最終將)覆蓋它們。 所以你不應該再訪問它們了。

如果在退出函數后需要分配的內存保持不變,則使用堆。

局部變量temp在函數開始時被“推”到堆棧上,並在函數退出時“彈出”堆棧。

這是非優化版本的反匯編:

int addTwo(int num)
{
00411380  push        ebp  
00411381  mov         ebp,esp             //Store current stack pointer
00411383  sub         esp,0CCh            //Reserve space on stack for locals etc
00411389  push        ebx  
0041138A  push        esi  
0041138B  push        edi  
0041138C  lea         edi,[ebp-0CCh] 
00411392  mov         ecx,33h 
00411397  mov         eax,0CCCCCCCCh 
0041139C  rep stos    dword ptr es:[edi] 
    int temp = 2;
0041139E  mov         dword ptr [temp],2 
    num += temp;
004113A5  mov         eax,dword ptr [num] 
004113A8  add         eax,dword ptr [temp] 
004113AB  mov         dword ptr [num],eax 
    return num;
004113AE  mov         eax,dword ptr [num] 
}
004113B1  pop         edi  
004113B2  pop         esi  
004113B3  pop         ebx  
004113B4  mov         esp,ebp                 //Restore stack pointer
004113B6  pop         ebp  
004113B7  ret        

術語“推”和“彈出”僅僅意味着類比。 從匯編輸出中可以看出,編譯器通過從堆棧指針中減去合適的值,一次性保留局部變量等的所有內存。

一旦函數退出,它就不會從內存中刪除。

它保留在內存中,在addTwo的堆棧幀中,直到某個其他進程(或相同)重新使用該部分內存。

在此之前,訪問temp是未定義的行為。

temp在堆棧上分配。 所以當函數返回時,它就消失了。

C ++范圍規則與C#類似。

請看我對這個問題的回答。 這可能會為oyu清理很多東西。

自動內存分配如何在C ++中實際工作?

我不只是發布咯咯笑的鏈接。 我的答案是深入了解(在介紹性層面)內存管理的工作原理。

通常,內存管理用於創建的動態內存的上下文中

new
malloc

正常的代碼中,C ++的行為與其他語言類似。 如果您創建變量或將其返回,則會在目標端復制並訪問該變量。

int a = addTwo(3);

獲取返回值的副本。 如果返回的值是一個調用的類復制操作符。 因此,只要你不使用new和malloc,你就不必那么關心內存管理了。

另外一個重要的評論

void func(std::string abc)
{
  // method gets a copy of abc
}

void func(std::string& abc)
{
  // method gets the original string object which can be modified without having to return it
}

void func(const std::string& abc)
{
  // method gets the original string object abc but is not able to modify it    
}

這三行的區別非常重要,因為您的程序可能會花費大量時間創建通常不想創建的輸入參數副本。

例如

bool CmpString(std::string a, std::string b)
{
  return a.compare(b);
}

是非常昂貴的,因為字符串a和b總是被復制。 使用

bool CmpString(const std::string& a, const std::string& b)

代替。

這很重要,因為默認情況下不使用refcounted對象。

變量temp是堆棧分配的。 這意味着它在函數返回時被釋放。

見例如:

在這種情況下,num和temp都是此函數的本地。 調用該函數時,傳入num的數字將從調用者復制到堆棧上的變量。 然后在堆棧上創建Temp。 返回時,num的值被復制回調用者,並且函數中使用的temp和num變量將被刪除。

在C中,C ++ 局部變量具有自動存儲類並存儲在Stack中

當函數返回時,堆棧被解開並且本地不再可訪問,但它們仍然存在於內存中,這就是當你在函數中定義變量時它可能包含垃圾值的原因。

它只是堆棧中的堆棧指針操作,實際上是刪除了本地的內存。

在C ++中,任何作用域中聲明的任何對象都將在作用域退出時被刪除。 在下面的示例中,在聲明對象時調用默認構造函數,並在退出時調用析構函數,即~MyClass。

void foo() {
  MyClass object;
  object.makeWonders();
}

如果在函數中聲明指針,那么當范圍退出時,指針本身(32位系統的4個字節)會被回收,但是您可能使用operator new或malloc分配的內存將會延遲 - 這通常稱為內存泄漏。

void foo() {
  MyClass* object = new MyClass;
  object->makeWonders();
  // leaking sizeof(MyClass) bytes.
}

如果你真的必須通過new分配一個對象,當它退出范圍時需要刪除,那么你應該使用boost :: scoped_ptr,如下所示:

void foo() {
  boost::scoped_ptr<MyClass> object(new MyClass);
  object->makeWonders();
  // memory allocated by new gets automatically deleted here.
}

暫無
暫無

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

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