[英]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.