簡體   English   中英

C ++內存管理和向量

[英]C++ memory management and vectors

我對與向量有關的內存管理感到非常困惑,可以用一些基本的概念來解釋。

我有一個使用大向量的程序。 我使用new運算符創建了向量,並在程序結束時使用delete釋放它們以獲取內存。

我的問題是,如果程序因任何原因崩潰或中止, 刪除行將被遺漏,是否有辦法恢復內存,即使在這種情況下。

我還有一些其他大的向量,我沒有new關鍵字。 我已經讀過這些將在堆上創建,但無論如何都不需要解除分配,因為內存管理是在“引擎蓋下”處理的。 但是我不確定是這種情況,因為每次運行我的程序時我都會失去RAM。

所以我的第二個問題是,沒有new關鍵字創建的向量是否真的留給他們自己的設備,並且即使代碼在流程中被中止,也可以信任自己清理。

我想剛剛想到的第三個問題是,如果在堆上自動創建了Vectors,你為什么要在它們中使用new關鍵字呢? 謝謝你的閱讀,本

我懷疑你的問題是關於std :: vector <T>(而不是數組T [])。

  1. 當您的應用程序因任何原因崩潰或中止時,操作系統會回收內存。 如果不是,您使用的是真正罕見的操作系統,並發現了一個錯誤。
  2. 您需要區分向量本身使用的內存和其包含的對象的內存。 正如您所指出的那樣,可以在堆上或堆棧上創建向量,它為其包含的元素分配的內存始終在堆上(除非您提供自己的分配器來執行其他操作)。 向量分配的內存由向量的實現管理,如果向量被破壞(因為它超出了堆棧上的向量的范圍,或者因為你刪除了堆上的向量),它的析構函數確保所有內存被釋放。

不要使用new來創建向量。 把它們放在堆棧上。

向量的析構函數自動調用向量中每個元素的析構函數。 因此您不必擔心自己刪除對象。 但是,如果您有一個指針向量,則指針所引用的對象將不會被清除。 這是一些示例代碼。 為清楚起見,我遺漏了大部分細節:

class HeapInt
{
    public:
        HeapInt(int i) {ptr = new int(i);}
        ~HeapInt() {delete ptr;}
        int& get() {return *ptr;}
    private:
        int* ptr;
};

int main()
{
    // this code DOES NOT leak memory
    std::vector<HeapInt> vec;
    for (int i = 0; i < 10; ++i)
    {
       HeapInt h(i);
       vec.push_back(h);
    }
    return 0;
}

即使main()拋出異常,也不會丟失內存。 但是,此代碼確實泄漏了內存:

int main()
{
    // this code though, DOES leak memory
    std::vector<int*> vec;
    for (int i = 0; i < 10; ++i)
    {
       int* ptr = new int(i);
       vec.push_back(ptr);
    }
    // memory leak: we manually invoked new but did not manually invoke delete
    return 0;
}

是的,你可以相信矢量自己清理。

然而,你不能相信矢量持有清理后的東西。 需要清理的內容可能會在您的應用程序之外持續存在。 如果它的記憶,這不是一個擔心。 如果它確保XML標簽全部關閉,那么操作系統將無法幫助您。

例如,如果你有一個像這樣的一個不穩定的鎖對象的向量怎么辦:

  class CLock
  {
  public:
      CLock() {}
      ~CLock() {}

      void Lock(...) {...}

      void Unlock(...) {...}
  };

  std::vector<CLock> myLockVec;

你的CLock的矢量如何在完成時解鎖所有內容? Vector不是為了解鎖而構建的。

這與具有指針向量的情況基本相同:

 std::vector<int*> myIntVec;

向量如何知道這里的哪些指針已被刪除並且為NULL,哪些指針真的存在? 也許有些已被刪除並設置為您的特殊值0xdeadbeef,意味着已刪除。

關鍵是向量無法知道這個或知道它的元素是指針或鎖或其他什么。 它們只需要具有默認構造函數且可復制的東西,並滿足vector對其元素的其他此類要求。

解決方案是確保任何向量HOLDS都需要負責其清理。 這稱為RAII - 資源分配是初始化,更重要的是,資源銷毀是解除分配。 通過上面我們的CLock示例,答案是顯而易見的,確保在我們完成后解鎖!

 class CLock
 {  
      ...
      ~Clock()
      {
          if (locked)
          {
              Unlock();
          }
      }
 } 

但是指針並不那么明顯。 解決方案是將指針包裝在smart_ptr類中。 其中最多產的是聰明的poniters助推器系列

class CSmartPointer<T>
{
      CSmartPointer( T* rawPtr)
      {
         m_ptr = rawPtr;
      }

      ~CSmartPointer()
      {
         delete m_ptr;
      }
}

附加功能通過引用計數等指針發揮作用,但上面的示例應該為您提供問題性質的要點以及它通常如何解決。

程序創建的任何內存將在退出時釋放。 這是操作系統的一個功能,與您正在使用的編程語言無關。

“每次我運行我的程序時,我都會松開RAM”必定是由於其他一些影響 - 你是如何測量的?

至於為什么要使用“新” - 有兩個原因:

  • 您希望控制它們何時被釋放
  • 您希望它們在當前函數退出后保持不變。

我想你談的是std :: vector而不是語言數組。

  1. 當程序崩潰時,操作系統會恢復其內存
  2. std :: vector釋放它分配的內存。 如果要存儲指針,則不會刪除它們。
  3. 向量是作為任何其他變量創建的,它們不在堆中,因為它們是向量。

我們兩個中的一個在這里有點困惑。

如果使用std :: vector,則無需為其元素手動分配內存。 每當您執行push_back()時,將在需要時自動分配額外空間。 如果由於某種原因需要預先分配所有空間,可以調用reserve()。 無論哪種方式,當向量被破壞時,內存會自動為您釋放。

如果你正在做新的std :: vector,你將獲得一個指向向量的指針。 這與在任何其他類上調用new沒有什么不同。 您創建一個指向該類對象的指針,當您調用delete時它將被破壞。 如果您不喜歡這種行為,請嘗試在堆棧上創建向量。

對於“失去記憶”,@ RichieHindie說。

對於第二個問題:

可以將沒有NEW關鍵字創建的向量留給他們自己的設備,並且即使代碼在流程中被中止,也可以信任他們自己清理

雖然正常的程序終止(包括異常終止)確保析構函數執行(對於靜態數據的那些有一些狡辯 - 理論上那些也應該運行,實際上你可能偶爾會遇到問題),這個過程的足夠嚴重的崩潰不能保證任何行為 - 例如, kill -9 保證盡快終止你的程序,而不給它機會執行任何析構函數或其他任何東西。

在某些情況下,當vector是類的成員變量時,未提及的另一個場景是關於何時使用“new”。 NULL可用作附加信號量,例如在按需創建期間; 另外,如果向量稀疏地填充了類,那么除非真正需要它,否則甚至不創建一個將節省內存,代價是對所有實例額外的4字節懲罰以及指針間接的運行時懲罰。

暫無
暫無

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

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