簡體   English   中英

為什么在 function 之后堆上的元素沒有釋放?

[英]Why aren't elements on the heap released after the function?

有人告訴我‘是的。 node* new_node = new node; 在堆上分配一個節點, node new_node; function 在堆棧上分配一個節點。 如果節點相互指向,它仍然是一個鏈表。 請注意,當 function 結束時,堆棧分配的內容會自動釋放。 這就是為什么在堆上分配更方便的原因。

這是什么意思? 有人可以詳細說明嗎?

龍回答。

自動存儲時間

一旦您離開聲明它們的 scope,“堆棧”變量(更恰當地稱為具有自動存儲持續時間的實體)就會被銷毀。 (即他們被“清理”,他們的memory被釋放)

void my_function() {
  node node1;
  if (1 == 1) {
      node node2;
      node* node3_ptr = new node; // this node is *not* cleaned up automatically
  } // node2 is destructed now
  node node4;
} // node1 and node4 are destructed now

在上面的代碼中, node1node4聲明在 function 的最外層 scope 的不同部分。 當函數結束時,它們將“消失”。

function是否運行到最后,提前返回,拋出異常無關緊要 - 如果function結束,C++保證它們將被銷毀。 (終止在其軌道上的應用程序是不同的。)

node2if塊內聲明。 當代碼離開if塊時,它將被銷毀——甚至在 function 結束之前。

這保證在完全可預測的時間自動銷毀這些變量是 C++ 的最大優勢之一。 它被稱為“確定性破壞”,這也是我首選語言 C++ 的原因之一。

動態存儲時長

“堆”變量(也就是具有“動態”存儲位置的實體)比較棘手。

void my_leaky_function() {
  node* node5;

  new node;

  node* node6 = new node;
}

node5仍然只是一個局部變量。 它的類型是“指向節點的指針”而不僅僅是“節點”這一事實並不重要。 它是一個具有自動持續時間的變量,使用 memory。 它的大小是指針的大小(可能是 4 或 8 個字節 - 取決於您的平台),而不是節點的大小。 當 function 結束時,該變量“消失”並且其 memory 被恢復。

new node; 在“免費存儲”(俗稱“堆”)上分配 memory。 new返回一個指向已分配 memory 的指針,但此代碼忽略該指針。 這里不涉及局部變量,function結束時節點銷毀;

node* node6 = new node; 還為自由存儲上的節點 object 分配了足夠的空間 - 但這次new返回的指針存儲在名為node6的局部變量中。 注意: node6是一個局部變量(存儲指針,而不是節點),它具有自動存儲持續時間。 當 function 結束時, node6變量消失(並且它使用的 memory 的幾個字節被釋放)。 但是node6也指向的節點 - 存儲在免費存儲中的節點 -沒有被破壞。

當這個 function 結束時,它在空閑存儲中留下了兩個節點 - 因為它已經丟棄了指向每個節點的指針,所以任何人都無法刪除它們。 它有“泄漏的記憶”。

為什么要使用動態存儲?

C++ 承諾在您離開 scope 時清理函數的自動存儲值。 這通常是你想要的。

有時 function 需要創建一個比 function 調用更有效的值 - 當 function 退出時不得銷毀該值。

通常,該值可以只返回給調用者(沒有new ,沒有指針),調用者可以用它做他們想做的事。 通常,該值存儲在某個集合中,例如已經為其分配了 memory 的向量或數組。 但是 - 在您的示例中,您想在鏈表或樹(或類似的東西)中創建一個新節點,並且在 function 結束時銷毀該節點是沒有意義的。

tl;博士;

所以

  1. 如果一個值必須在創建它的 function 結束后存在
  2. 它不僅僅是返回給函數的調用者
  3. 並且它沒有存儲在其他容器的 memory 中

那么免費商店就是合適的地方。

go 關於誰“擁有”該值並負責刪除它 - 以及使用智能指針而不是原始指針 - 以及異常安全 - 和和 - 但這個答案已經比我更大了通緝。 所以讓我以這個結束:

在學習 C++ 時,請使用指針。 使用免費商店。 用 memory 泄漏和雙重刪除燒毀自己。 弄清楚你將如何解決這些問題。 這為您理解稍后將使用的抽象奠定了良好的基礎。

一旦你了解了指針和動態存儲——一旦你了解了如何從頭開始編寫自己的鏈表或二叉樹——停止使用它們。 在日常編碼中,除非您是為容器庫編寫代碼的專家,否則永遠不要再次使用newdelete 絕對必要時使用智能指針,但盡量避免使用它們。

盡可能依靠自動存儲持續時間。 確定性破壞是你的朋友。 這就是 C++ 與 C 的區別所在。 這就是 C++ 與垃圾收集語言的區別所在。 這就是為什么 C++ 仍然是編程語言之王之一的原因。

您仍然可以讓指針在之前的方法調用中引用相同的 object。

暫無
暫無

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

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