C++ memory management and vectors

23,858

Solution 1

I suspect your questions are about std::vector< T > (as opposed to an array T[]).

  1. When your application crashes or gets aborted for whatever reason, the OS reclaims the memory. If not you are using a truly rare OS and have discovered a bug.
  2. You need to distinguish between the memory used by the vector itself and the memory of its contained objects. The vector can be created on the heap or on the stack as you noted, the memory it allocates for its contained elements is always on the heap (unless you provide your own allocator which does something else). The memory allocated by the vector is managed by the implementation of vector, and if the vector is destructed (either because it goes out of scope for a vector on the stack or because you delete a vector on the heap) its destructor makes sure that all memory is freed.

Solution 2

Don't use new to create vectors. Just put them on the stack.

The vector's destructor automatically invokes the destructor of each element in the vector. So you don't have to worry about deleting the objects yourself. However, if you have a vector of pointers, the objects that the pointers refer to will not be cleaned up. Here's some example code. For clarity I am leaving out most details:

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;
}

Even if main() throws an exception, no memory is lost. However, this code does leak memory:

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;
}

Solution 3

Yes you can trust vectors to clean up after themselves.

HOWEVER You cannot trust the stuff vector holds to cleanup after itself. What needs to be cleaned up could be something that persists outside of your application. If its memory, this isn't a worry. If its making sure the XML tags are all closed, then the OS isn't going to be able to help you.

For example, what if you have a vector of some wonky lock object like this:

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

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

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

  std::vector<CLock> myLockVec;

How would your vector of CLock's know to unlock everything when its done? Vector's aren't built to know about locks.

This is essentially the same situation as having a vector of pointers:

 std::vector<int*> myIntVec;

How does the vector know which pointers here have been deleted and NULL'd, and which ones are really there? Maybe some have been deleted and set to your special value 0xdeadbeef, meaning deleted.

The point is the vector has no means to know this or know that its elements are pointers or locks or whatever. They just need to be things that have default constructors and are copyable, and meet the other such requirements that vector has on its elements.

The solution is to be sure that whatever vector HOLDS needs to be responsible for its cleanup. This is called RAII -- Resource Allocation Is Initialization, more importantly here, Resource Destruction is Deallocation. With Our CLock example above, the answer is obvious, be sure to unlock when we're done!

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

But with pointers its not so obvious. The solution is to wrap up the pointer in a smart_ptr class. The most prolific of these are the boost family of smart poniters.

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

      ~CSmartPointer()
      {
         delete m_ptr;
      }
}

Additional features are brought into play with pointers such as reference counting, but the above example should give you the gist of the nature of the problem and how its typically solved.

Solution 4

I suppose that you talk about the std::vector and not about language arrays.

  1. When a program crashes, the OS recovers its memory
  2. std::vector releases the memory that it allocates. If you are storing pointers, they will not be deleted.
  3. Vectors are created as any other variable, they are not in the heap only because they are vectors.

Solution 5

Any memory created by your program will be released when it exits. That's a feature of the Operating System, nothing to do with the programming language you're using.

"every time I run my program I loose RAM" must be due to some other effect - how are you measuring that?

As to why you'd use "new" - two reasons:

  • You want to control when they are freed
  • You want them to persist after the current function exits.
Share:
23,858
Columbo
Author by

Columbo

Updated on July 05, 2022

Comments

  • Columbo
    Columbo almost 2 years

    I'm getting very confused with memory management in relation to vectors and could do with some basic concepts explaining.

    I have a program that uses big vectors. I created the vectors with the new operator and release them at the end of the program with delete to get the memory back.

    My question is, if the program crashes or gets aborted for what ever reason, the delete lines will be missed, is there a way to recover the memory even in this scenario.

    I also have some other large vectors that I assign without the new keyword. I have read that these will be created on the heap but do not need to be deallocated in anyway as the memory management is dealt with 'under the hood'. However I am not sure this is the case as every time I run my program I lose RAM.

    So my second question is, can vectors created without the new keyword really be left to their own devices and trusted to clear up after themselves even if code is aborted mid flow.

    And I suppose a third question that has just sprung to mind is, if Vectors are automatically created on the heap why would you ever use the new keyword with them? Thanks for reading, ben