[英]C++ memory management and vectors
我對與向量有關的內存管理感到非常困惑,可以用一些基本的概念來解釋。
我有一個使用大向量的程序。 我使用new運算符創建了向量,並在程序結束時使用delete釋放它們以獲取內存。
我的問題是,如果程序因任何原因崩潰或中止, 刪除行將被遺漏,是否有辦法恢復內存,即使在這種情況下。
我還有一些其他大的向量,我沒有new關鍵字。 我已經讀過這些將在堆上創建,但無論如何都不需要解除分配,因為內存管理是在“引擎蓋下”處理的。 但是我不確定是這種情況,因為每次運行我的程序時我都會失去RAM。
所以我的第二個問題是,沒有new關鍵字創建的向量是否真的留給他們自己的設備,並且即使代碼在流程中被中止,也可以信任自己清理。
我想剛剛想到的第三個問題是,如果在堆上自動創建了Vectors,你為什么要在它們中使用new關鍵字呢? 謝謝你的閱讀,本
我懷疑你的問題是關於std :: vector <T>(而不是數組T [])。
不要使用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而不是語言數組。
我們兩個中的一個在這里有點困惑。
如果使用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.