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
I suspect your questions are about std::vector< T > (as opposed to an array T[]).
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;
}
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.
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:
I suppose that you talk about the std::vector and not about language arrays.
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.
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.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.