C++内存管理和向量

Col*_*mbo 5 c++ memory vector

我对与向量有关的内存管理感到非常困惑,可以用一些基本的概念来解释.

我有一个使用大向量的程序.我使用new运算符创建了向量,并在程序结束时使用delete释放它们以获取内存.

我的问题是,如果程序因任何原因崩溃或中止,删除行将被遗漏,是否有办法恢复内存,即使在这种情况下.

我还有一些其他大的向量,我没有new关键字.我已经读过这些将在堆上创建,但无论如何都不需要解除分配,因为内存管理是在"引擎盖下"处理的.但是我不确定是这种情况,因为每次运行我的程序时我都会失去RAM.

所以我的第二个问题是,没有new关键字创建的向量是否真的留给他们自己的设备,并且即使代码在流程中被中止,也可以信任自己清理.

我想刚刚想到的第三个问题是,如果在堆上自动创建了Vectors,你为什么要在它们中使用new关键字呢?谢谢你的阅读,本

Tob*_*ias 16

我怀疑你的问题是关于std :: vector <T>(而不是数组T []).

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

  • 当进程崩溃时,大多数嵌入式操作系统和许多RTOS都不会清理资源. (4认同)

rlb*_*ond 10

不要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;
}
Run Code Online (Sandbox Code Playgroud)

即使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;
}
Run Code Online (Sandbox Code Playgroud)

  • 是的,但问清楚的人并不知道矢量应该被放在堆栈上. (5认同)
  • 是的,当任何程序结束时,操作系统会回收内存.但如果这是程序多次调用的函数,则会出现内存泄漏. (3认同)

Dou*_* T. 5

是的,您可以信任媒介来清除它们。

但是,您不能相信填充向量本身可以保留下来进行清理。需要清除的内容可能是在应用程序之外仍然存在的内容。如果有它的记忆,那就不用担心了。如果确保XML标记均已关闭,则操作系统将无法为您提供帮助。

例如,如果您有一个像这样的不稳定锁对象的矢量:

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

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

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

  std::vector<CLock> myLockVec;
Run Code Online (Sandbox Code Playgroud)

完成后,您的CLock载体如何知道如何解锁?向量的构建并不是为了了解锁。

这与具有指针向量的情况基本相同:

 std::vector<int*> myIntVec;
Run Code Online (Sandbox Code Playgroud)

向量如何知道此处的哪些指针已被删除并为NULL,以及真正存在的指针?也许某些已被删除并设置为您的特殊值0xdeadbeef,表示已删除。

关键是向量没有办法知道这个或知道它的元素是指针或锁或其他任何东西。它们只需要是具有默认构造函数且可复制的东西,并满足vector对其元素具有的其他此类要求。

解决方案是确保任何向量HOLDS都要负责其清理。这称为RAII-资源分配是初始化,更重要的是,资源破坏是释放。在上面的“我们的CLock”示例中,答案很明显,一定要在完成后解锁!

 class CLock
 {  
      ...
      ~Clock()
      {
          if (locked)
          {
              Unlock();
          }
      }
 } 
Run Code Online (Sandbox Code Playgroud)

但是使用指针并不是那么明显。解决方案是将指针包装在smart_ptr类中。其中最多产的是精明针线虫boost系列

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

      ~CSmartPointer()
      {
         delete m_ptr;
      }
}
Run Code Online (Sandbox Code Playgroud)

诸如引用计数之类的指针还具有其他功能,但是上面的示例应使您了解问题的本质以及通常如何解决该问题。