views:

854

answers:

8

Hi All, 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

+2  A: 

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.
RichieHindle
Same comment as given to Tobias. Most embedded OSes and many RTOS's don't clean up resources when a process crashes.
T.E.D.
+1 for pointing out what many don't realize. A virtual memory manager is a luxury often taken for granted.
Void
+2  A: 

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.
Artur Soler
+2  A: 

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.

Doug T.
A: 

For the "lost memory", what @RichieHindie says.

For the second question:

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

While normal program termination (including termination by exception) ensures that destructors execute (with some quibbles regarding those for static data -- in theory those should run too, in practice you might occasionally get problems), a sufficiently hard crash of the process cannot guarantee any behavior -- for example, a kill -9 is guaranteed to terminate your program ASAP, without giving it the chance to execute any destructors or anything else.

Alex Martelli
Unhandled exceptions (ones that cause the runtime to eventually call terminate() ) may not cause destructors to execute. The stack unwinding behavior in this case is implementation-defined.
ASk
+6  A: 

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.
Tobias
Most embedded OSes and many RTOS's don't clean up resources when a process crashes.
T.E.D.
+5  A: 

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 DOES NOT 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;
}
rlbond
That doesn't always work.
David Thornley
Yes, but the person asking the question clearly doesn't know that vectors should USUALLY be put on the stack.
rlbond
+1  A: 

One of the two of us is a bit confused here.

If you are using std::vector, you don't need to manually allocate memory for its elements. Extra space will automaticly be allocated when needed whenever you do a push_back(). If you need all space preallocated for some reason, you can call reserve(). Either way, the memory gets freed automagically for you when the vector is destructed.

If you are doing new std::vector, you are getting a pointer to the vector. That is no different than calling new on any other class. You create a pointer to an object of that class, and it will get destructed when you call delete. If you don't like that behavior, try creating your vector on the stack.

T.E.D.
A: 

Another scenario not mentioned in regards to when you'd want to use "new", is in some cases when a vector is a member variable of a class. The NULL can be used as an additional semaphore, for example during create on demand; also, if the vector usage is sparsely populated on your class, then not even creating one unless it's really needed will save you memory, at the expense of the extra 4 byte penalty on all instances as well as the runtime penalty of the pointer indirection.

no-op