2009-06-08 73 views
5

我对与向量有关的内存管理感到困惑,并且可以用一些基本概念来解释。C++内存管理和向量

我有一个使用大向量的程序。 我创建的载体与运营商,并在程序与年底释放他们删除让内存回来。

我的问题是,如果程序崩溃或中止对什么都原因,删除线将被错过,有没有办法恢复的内存,即使在这种情况下。

我也有一些其他的大型矢量,我没有分配新的关键字。 我已经读过,这些将在堆上创建,但无论如何都不需要解除分配,因为内存管理是在'引擎盖下'处理的。 但是我不确定这是怎么回事,因为每次运行程序时我都会丢失RAM。

所以我的第二个问题是,可以在不关键字创建矢量真正留给自己的设备和信任后自己清理,即使代码被中止中旬流。

而且我想,刚刚跳出来的心是,如果载体是自动上堆上创建,为什么你会永远使用关键字与他们的第三个问题? 感谢您的阅读, ben

+2

通过“每次我跑我的程序的时候我失去RAM”你的意思或“我的可用RAM获取即使我退出程序小“直到我退出程序我的可用内存变小”了,它变得更小了下一次我跑,直到有一天,我将完全没有内存剩下“? – 2009-06-08 19:31:45

+0

我借调Max的问题​​。 Windows我相信实际上并没有卸载已终止的程序,除非需要。这样他们在第一次之后就开始更快。 – 2009-06-08 19:48:18

+0

“我想第三个问题刚刚想到,如果矢量是自动创建在堆上,为什么你会使用新的关键字?” 如果您需要将矢量传递到当前范围之外的某个点,则只需执行此操作。这在实践中比较少见。 – rlbond 2009-06-09 04:09:28

回答

13

我怀疑你的问题是关于标准::矢量< T>(相对于阵列T [])。

  1. 当您的应用程序因任何原因崩溃或中止时,操作系统将回收内存。如果不是,你正在使用一个真正难得的操作系统,并发现了一个错误
  2. 您需要区分矢量本身使用的内存和其包含的对象的内存。可以在堆中或堆栈上创建矢量,它为其包含的元素分配的内存始终位于堆上(除非您提供自己的分配器来执行其他操作)。由矢量分配的内存由矢量的实现来管理,如果矢量被破坏(或者因为它超出了堆栈中矢量的范围,或者因为你删除了堆中的矢量),它的析构函数确保所有内存被释放。
3

您程序创建的任何内存将在退出时被释放。这是操作系统的一项功能,与您使用的编程语言无关。

“每次我运行我的程序我松散RAM”一定是由于一些其他影响 - 你怎么测量?

至于为什么你会使用“新” - 两个原因:

  • 你想,当他们被释放
  • 你希望他们当前函数退出后持续控制。
+1

与Tobias相同的评论。大多数嵌入式操作系统和许多RTOS在进程崩溃时不会清理资源。 – 2009-06-08 17:28:52

+0

+1指出许多人没有意识到。虚拟内存管理员是奢侈品,通常被认为是理所当然的。 – Void 2009-06-08 19:37:01

3

我想你说的是std :: vector而不是语言数组。

  1. 当一个程序崩溃,则OS恢复其存储器
  2. 的std ::矢量释放其分配内存。如果你正在存储指针,它们不会被删除。
  3. 向量被创建为任何其他变量,它们不在堆中,因为它们是向量。
4

是的你可以信任载体自行清理。

然而你不能相信东西矢量持有自己清理之后。需要清理的内容可能会在应用程序之外持续存在。如果它的记忆,这不是一个担心。如果确保XML标签全部关闭,那么操作系统将无法为您提供帮助。

例如,如果你有这样的一些靠不住的锁定对象的向量:

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

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

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

    std::vector<CLock> myLockVec; 

如何将其完成时,你的时钟的专有的矢量解开一切吗? Vector的构建不了解锁。

这本质上是相同的情况下具有指针的向量:

std::vector<int*> myIntVec; 

如何矢量知道哪些指针这里已被删除,NULL'd,以及哪些是真的吗?也许有些已被删除并设置为您的特殊值0xdeadbeef,意思是删除。

的点是向量没有手段知道这个或知道其元素是指针或锁或任何。他们只需要具有默认构造函数并且是可复制的,并且满足向量对其元素的其他这样的需求。

解决方案是可以肯定的,无论矢量HOLDS需要负责其清理。这叫做RAII - 资源分配是初始化,在这里更重要的是资源销毁是取消分配。通过上面的CLock示例,答案很明显,一定要在完成时解锁!

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

但是指针其实并不那么明显。解决方案是将指针包装在smart_ptr类中。其中最多产的是boost family of smart poniters

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

     ~CSmartPointer() 
     { 
     delete m_ptr; 
     } 
} 

附加功能得到了充分的指针如引用计数,但上面的例子应该给你的问题的性质的要点以及如何它的典型解决。

1

对于 “失去的记忆”,什么@RichieHindie说。

对于第二个问题:

可以在没有新的关键字创建载体真的留给自己 自己的设备和信任后自己清理即使代码 中止中期流动

当程序正常终止(包括异常终止)确保析构函数执行(与关于那些静态数据的一些狡辩 - 在理论上这些应该太运行,实际上,你可能偶尔会问题)时,p的足够硬的碰撞rocess不能保证任何行为 - 例如,一个kill -9保证尽快终止您的程序,没有给它机会执行任何析构函数或任何其他。

8

不要使用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()抛出异常,也不会丢失内存。但是,此代码确实泄漏内存:

​​3210
2

一个我们两个是在这里有点糊涂了。

如果您使用的std ::向量,你不需要为它的元素以手动分配内存。无论何时执行push_back(),都会自动分配额外空间。如果您因某种原因需要预先分配所有空间,则可以调用reserve()。无论哪种方式,当矢量被破坏时,内存都会自动释放。

如果你正在做新的std ::向量,你得到一个指针向量。这与在任何其他班级上呼吁新人没有什么不同。你创建一个指向这个类的对象的指针,当你调用delete的时候它会被破坏。如果你不喜欢这种行为,尝试在堆栈上创建你的矢量。

1

的问候没有提到,当你想使用“新”的另一种情况,在某些情况下,当一个向量是一个类的成员变量。 NULL可以用作额外的信号量,例如在按需创建期间;另外,如果向量用法稀疏地填充到类上,那么甚至不创建一个,除非真正需要它将节省您的内存,代价是所有实例上额外的4字节惩罚以及指针间接引发的运行时间损失。