I am totally confused with regards to deleting things in C++. If I declare an array of objects and if I use the clear() member function. Can I be sure that the memory was released?
For example :
tempObject obj1;
tempObject obj2;
vector<tempObject> tempVector;
tempVector.pushback(obj1);
tempVector.pushback(obj2);
Can I safely call clear to free up all the memory? Or do I need to iterate through to delete one by one?
tempVector.clear();
If this scenario is changed to a pointer of objects, will the answer be the same as above?
vector<tempObject> *tempVector;
//push objects....
tempVector->clear();
You can call clear, and that will destroy all the objects, but that will not free the memory. Looping through the individual elements will not help either (what action would you even propose to take on the objects?) What you can do is this:
vector<tempObject>().swap(tempVector);
That will create an empty vector with no memory allocated and swap it with tempVector, effectively deallocating the memory.
C++11 also has the function shrink_to_fit, which you could call after the call to clear(), and it would theoretically shrink the capacity to fit the size (which is now 0). This is however, a non-binding request, and your implementation is free to ignore it.
There are two separate things here:
object lifetime
storage duration
For example:
{
vector<MyObject> v;
// do some stuff, push some objects onto v
v.clear(); // 1
// maybe do some more stuff
} // 2
At 1, you clear v: this destroys all the objects it was storing. Each gets its destructor called, if your wrote one, and anything owned by that MyObject is now released.
However, vector v has the right to keep the raw storage around in case you want it later.
If you decide to push some more things into it between 1 and 2, this saves time as it can reuse the old memory.
At 2, the vector v goes out of scope: any objects you pushed into it since 1 will be destroyed (as if you'd explicitly called clear again), but now the underlying storage is also released (v won't be around to reuse it any more).
If I change the example so v becomes a pointer to a dynamically-allocated vector, you need to explicitly delete it, as the pointer going out of scope at 2 doesn't do that for you. It's better to use something like std::unique_ptr in that case, but if you don't and v is leaked, the storage it allocated will be leaked as well. As above, you need to make sure v is deleted, and calling clear isn't sufficient.
vector::clear() does not free memory allocated by the vector to store objects; it calls destructors for the objects it holds.
For example, if the vector uses an array as a backing store and currently contains 10 elements, then calling clear() will call the destructor of each object in the array, but the backing array will not be deallocated, so there is still sizeof(T) * 10 bytes allocated to the vector (at least). size() will be 0, but size() returns the number of elements in the vector, not necessarily the size of the backing store.
As for your second question, anything you allocate with new you must deallocate with delete. You typically do not maintain a pointer to a vector for this reason. There is rarely (if ever) a good reason to do this and you prevent the vector from being cleaned up when it leaves scope. However, calling clear() will still act the same way regardless of how it was allocated.
if I use the clear() member function. Can I be sure that the memory was released?
No, the clear() member function destroys every object contained in the vector, but it leaves the capacity of the vector unchanged. It affects the vector's size, but not the capacity.
If you want to change the capacity of a vector, you can use the clear-and-minimize idiom, i.e., create a (temporary) empty vector and then swap both vectors.
You can easily see how each approach affects capacity. Consider the following function template that calls the clear() member function on the passed vector:
template<typename T>
auto clear(std::vector<T>& vec) {
vec.clear();
return vec.capacity();
}
Now, consider the function template empty_swap() that swaps the passed vector with an empty one:
template<typename T>
auto empty_swap(std::vector<T>& vec) {
std::vector<T>().swap(vec);
return vec.capacity();
}
Both function templates return the capacity of the vector at the moment of returning, then:
std::vector<double> v(1000), u(1000);
std::cout << clear(v) << '\n';
std::cout << empty_swap(u) << '\n';
outputs:
1000
0
Move semantics allows for a straightforward way to release memory, by simply applying the assignment (=) operator from an empty rvalue:
std::vector<int> vec(100, 0);
std::cout << vec.capacity(); // 100
vec = vector<int>(); // Same as "vector<int>().swap(vec)";
std::cout << vec.capacity(); // 0
It is as much efficient as the "swap()"-based method described in other answers (indeed, both are conceptually doing the same thing). When it comes to readability, however, the assignment version makes a better job.
You can free memory used by vector by this way:
//Removes all elements in vector
v.clear()
//Frees the memory which is not used by the vector
v.shrink_to_fit();
If you need to use the vector over and over again and your current code declares it repeatedly within your loop or on every function call, it is likely that you will run out of memory. I suggest that you declare it outside, pass them as pointers in your functions and use:
my_arr.resize()
This way, you keep using the same memory sequence for your vectors instead of requesting for new sequences every time.
Hope this helped.
Note: resizing it to different sizes may add random values. Pass an integer such as 0 to initialise them, if required.
Related
I come from a C background. I used to allocate memory/array, for example, sending it to somewhere else, and the pointer stayed there, even after, the scope where it was allocated was destroyed.
Now, if I do the same with vectors : initialize, pass it by reference, and then keep that reference saved somewhere. After the initial method, that actually created the vector, goes out of scope, would it be destroyed ? Or as the pointer to it is still saved, it will be kept.
std::vector frees the memory it holds when it is destroyed. Holding a reference to an object that gets destroyed is very bad. Accessing it is UB. General rule: Do not store references, only use them where you can be sure that the object exists for the entire scope, e.g. as parameter of a function.
If you want to keep a copy of the data, simply copy the std::vector. No reference needed.
If you want to be able to access the data from different locations, and have it live as long as at least one location still has a reference/pointer to it, don't use std::vector, use std::shared_ptr.
If you want to combine the benefits of std::vector with the benefits of shared memory that lives until the last place lets go of it, combine them: std::shared_ptr<std::vector<...>>.
If you want to have the std::vector live in one place for a bit, and then live in another place but not in the first place anymore, use move semantics:
std::vector<int> foo = {1, 2, 3};
std::vector<int> bar = std::move(foo); // bar now holds the data that foo held, foo is empty, no copy was performed
A pointer to an array on the stack will not keep the array alive, I suppose thats the same in C. Now a vector is not an array. It is a wrapper around a heap allocated array which frees the memory of the array when it goes out of scope.
... because a pointer to it is still saved it will still be kept?
No! A pointer or reference to a std::vector will not keep the vector alive. The canonical wrong example is:
std::vector<T>& foo() {
std::vector<T> x;
return x;
} // baaam !
The reference returned from the function is dangling. YOu cannot do anything with it. The correct way would be to return by value and rely on return value optimization:
std::vector<T> foo() {
std::vector<T> x;
return x;
}
If you do:
auto y = foo();
No copying is involved, thanks to NRVO.
PS: Compilers should warn you about returning a reference to a local variable.
No if I do the same with vectors, I initialize a vector, pass it by reference, then keep the reference saved somewhere. After the initial method that actually created the vector goes out of scope, would it be destoryed?
Yes.
or because a pointer to it is still saved it will still be kept?
No.
You can have dangling pointers in C++ just like you can in C. It's exactly the same.
This is also often the case for references (though in some cases the lifetime of the object is extended for a little bit).
It is true that the vector's data is internally managed by the vector, but that's by-the-by since you're asking about the vector itself. Forget the vector and ask the same question about an int, then you'll realise the answer is just as you'd expect it to be in C.
The existing answers are good, will add here:
block A
{
vector<int> my_vec(10, 0);
//...something...
}
block B
The my_vec vector will go out of scope and be destroyed at the closing bracket. Now that's stl (Standard Template Library) vectors.
You can also use C-style arrays (but with different syntax). For very large arrays, I have found the allocation time with a dynamically-allocated array to be faster than STL vectors.
//static, goes out of scope and memory handled at the end of code block
int arr0[10];
//dynamic, not destroyed unless delete called.
int* arr1 = new int[10];
//...work with arr1...
delete [] arr1;
Just like in C, you need to take care of de-allocating any memory you create using new.
For testing purposes, I was trying to create my own vector class, and I couldn't figure out how std::vector size reduction works.
class A
{
A()
{ std::cout << "A constructed") << std::endl; }
~A()
{ std::cout << "A destroyed") << std::endl; }
}
main()
{
std::vector<A> vec(3, A());
vec.resize(2);
std::cout << "vector resized" << std::endl;
}
Output is
A constructed (1)
A constructed (2)
A constructed (3)
A destroyed (1)
Vector resized
A destroyed (2)
A destroyed (3)
When vec.resize(2) is called, the third element is destroyed, but the vector's capacity is still 3. Then when vec is destroyed, all of its elements including the one already destroyed should be destroyed. How does std::vector know that he has already destroyed that element? How can I implement that in my vector class?
There's a difference between capacity and size. Given a std::vector<T> v; The vector has allocated memory for v.capacity() elements. But only in the first v.size() places contain constructed T objects.
So, v.reserve(1000) on an empty vector won't call any additional constructors. vec.resize(2) in your example destroys the last element and vec[2] is now an empty place in memory, but memory still owned by the vec.
I think your allocation looks like buffer = new T[newSize];. That is not how std::vector works which would not allow Ts that do not have default constructors. Maybe you did not realize this, but whenever you obtain a piece of memory, it already contains objects, let it be T x; or even new double[newSize]; which returns an array of doubles (although their constructors are empty).
There is only one way to get usable uninitialized memory in C++, which is to allocate chars. This is due to the strict aliasing rule. There also (is|must be) a way how to call a constructor explicitly on this memory i.e. how to create an object there. The vector uses something called placement new which does precisely that. The allocation is then simply buffer = new char[newSize*sizeof(T)]; which creates no objects whatsoever.
The lifetime of the objects is managed by this placement new operator and explicit calls to destructors.
emplace_back(arg1,arg2) could be implemented as {new(buffer + size) T(arg1,arg2);++size;}. Note that simply doing buffer[size]=T(arg1,arg2); is incorrect and UB. operator= expects that the left size(*this) already exists.
If you want to destroy an object with e.g. pop_back, you must do
buffer[size].~T();--size;. This is one of the very few places where you should call the destructor explicitly.
The simple answer is that vector internally manages constructor and destructor calls, often by using inplace operator new and operator delete methods.
Having popped an element, it is immediately descructed, and while the memory is still available, and may still contain some remnant values, std::vector itself knows which elements still need to be deleted, and won't call the destructor again.
When vec.resize(2) is called, the third element is destroyed, but the vector's capacity is still 3.
Yes. The capacity is how many elements the vector's internal array can physically hold. The size is how many elements in that array are actually valid. Shrinking the size does not affect the capacity at all.
Then when vec is destroyed, all of its elements including the one already destroyed should be destroyed.
The 3rd element that was previously destroyed and removed from the array is not destroyed again. Only size number of elements are destroyed, not capacity number of elements, like you are thinking.
How does std::vector know that he has already destroyed that element?
It tracks the size and capacity separately. When an element is removed from the array, the elements that follow it are moved down the array by 1 slot each, and the size is decremented.
This question already has answers here:
Should I always call vector clear() at the end of the function?
(5 answers)
Closed 4 years ago.
All of the questions that I have seen ask about managing memory when the elements of the vector are dynamically allocated/are pointers. My question is just about a vector that has been allocated on the stack, with a simple type, for example, int.
If I have the following code:
std::vector<int> vec(5);
for(int i = 0; i < vec.size(); i++) {
std::cout << vec[i] << std::endl;
}
Do I need to call clear() when I am done?
No.
Classes in C++ have a destructor that gets called when the class object goes out of scope or is deleted. While you are correct that std::vector dynamically allocates space under the hood, the std::vector destructor will deallocate the memory for you resulting in a happy leak-free program.
From the cppreference page, when the vector destructor is called it...
Destructs the container. The destructors of the elements are called and the used storage is deallocated. Note, that if the elements are pointers, the pointed-to objects are not destroyed.
Also note that from the cppreference on clear, the function...
Leaves the capacity() of the vector unchanged...
So when you call clear the memory isn't even actually being free'd! (see this SO question for more on what clear is actually doing)
If you are worried about freeing the memory allocated (and hence blocked for use elsewhere) in a (large) vector, you should
make sure the scope/lifetime of the respective vector is limited to the region/time of its imminent use, so that its destruction automatically frees the memory.
failing that (for whatever reason), you may
vec.clear(); // reduces the size to 0, but not the capacity
vec.shrink_to_fit(); // suggests to reduce the capacity to size
assert(vec.capacity()==0);
Note that vector::clear() de-allocates no memory in vector (only memory, if any, dynamically allocated by the vector elements). vector::shrink_to_fit() suggests the reduction of the memory footprint of vector to its actual size, but the implementation can chose to ignore that request.
Finally, an alternative to clear() followed by shrink_to_fit() is the swap idiom (which also works prior to C++11):
vector<Tp>().swap(vec);
assert(vec.capacity()==0);
What happens here is that a new empty vector (of the same type) is constructed and then immediately swapped with vec, so that vec becomes empty (with zero size and capacity). Finally, because the new vector is a temporary (un-named) object, it is destructed, whereby de-allocating the memory originally kept with vec.
I know that variables allocated on that stack of a function become inaccessible when the function finishes execution. However, vector types allocate their elements on the heap no matter how they are allocated. So for instance,
vector<int> A;
will allocate space for its elements on the heap instead of the stack.
My question is, assume I have the following code:
int main(int argc, char *argv[]) {
// initialize a vector
vector<int> A = initVector(100000);
// do something with the vector...
return 0;
}
// initialize the vector
vector<int> initVector(int size) {
vector<int> A (size); // initialize the vector "on the stack"
// fill the vector with a sequence of numbers...
int counter = 0;
for (vector<int>::iterator i = A.begin(); i != A.end(); i++) {
(*i) = counter++;
}
return A;
}
Will I have memory access problems when using the vector A in the main function? I tried this several times and they all worked normally, but I'm scared that this might just be luck.
The way I see it is, the vector A allocates its elements on the heap, but it has some "overhead" parameters (maybe the size of the vector) allocated on the stack itself. Therefore, using the vector in the main function might result in a memory access problem if these parameters are overwritten by another allocation. Any ideas?
When you do "return A;" you return by value, so you get a copy of the vector -- C++ creates a new instance and calls copy constructor or operator= on it. So in this case it doesn't matter where the memory was allocated as you have to copy it anyway and destroy the old copy (some possible optimizations notwithstanding).
The data in the vector (and all other STL containers) is moved around by value as well, so you store the copy of your integers, not pointers to them. That means your objects can be copied around several times in any container operation and they must implement a copy constructor and/or assignment operator correctly. C++ generates those for you by default (just calling copy ctor on all your member variables), but they don't always do the right thing.
If you want to store pointers in an STL container consider using shared pointer wrappers (std::shared_ptr or boost::shared_ptr). They will ensure the memory is handled correctly.
Yes, it will work normally because the memory for the elements are allocated and that is what will be used to build the vector<int> A = variable. However, performance wise, it is not the best idea.
I would suggest changing your function to be the following though
void initVector(vector<int>& a, int size)
For additional references on usage, please see Returning a STL vector from a function… and [C++] Returning Vector from Function.
For an additional reference on performance (using C++11), please see Proper way (move semantics) to return a std::vector from function calling in C++0x
C++ vector actually has two pieces of memory that are linked with a single pointer. The first one is in stack, and the 2nd one in heap. So you have features of both stack and heap in a single object.
std::vector<int> vec;
vec.push_back(10);
vec.push_back(20);
vec.push_back(30);
std::cout << sizeof(vec) << std::endl;
Once you run that code, you'll notice that the stack area does not contain the elements, but it still exists. So when you pass the vector from function to another, you'll need to manipulate the stack areas, and the vector will get copied like any other stack-based object.
The first solution is:
std::vector<int> *vec = new std::vector<int>;
assert(vec != NULL);
// ...
delete vec;
An alternative is:
std::vector<int> v;
//...
vec.clear();
vec.swap(std::vector<int>(vec));
The second solution's a bit of a trick --- what's the "right" way to do it?
Update:
I'm aware that the destructor will be called once it's off the stack, I was curious about other methods.
The simplest and most reliable way to deallocate a vector is to declare it on the stack and simply do nothing.
void Foo() {
std::vector<int> v;
...
}
C++ guarantees that the destructor of v will be called when the method executes. The destructor of std::vector will ensure any memory it allocated is freed. As long as the T type of the vector<T> has proper C++ deallocation semantics all will be well.
The simplest way to deallocate all the storage in a vector, without destroying the vector object itself, is
vec = std::vector<int>();
Your second variant will have the same effect, but it jumps through more hoops on the way. The "copy and swap" trick deallocates any extra capacity in the vector, and can be useful if it contains some data you want to keep. If there's no data, then there's no need for copying or swapping.
std::vector<int> vi;
/*push lots of stuff into the vector*/
// clean it up in C++03
// no need to clear() first
std::vector<int>().swap(vi);
// clean it up in C++0x
// not a one liner, but much more idiomatic
vi.clear();
vi.shrink_to_fit();
I agree with Mike Seymour
try this then you will notice that the last is working fine
const int big_size = 10000;
vector<double> v( big_size );
cout << "Before clearing, the capacity of the vector is "
<< v.capacity() << " and its size is " << v.size();
v.clear();
cout << "\nAfter clearing, the capacity of the vector is "
<< v.capacity() << " and its size is " << v.size();
vector<double>().swap( v );
cout << "\nAfter swapping, the capacity of the vector is "
<< v.capacity() << " and its size is " << v.size();
vector<double> v1( big_size );
v1 = vector<double>();
cout << "\n After vector<double>();, the capacity of the vector is "
<< v1.capacity() << " and its size is " << v1.size();
My guess here is that you have a vector which temporarily contains a large amount of data. Once the vector has been cleared, it will still take up all of this memory. You want to release this memory after you are done with it, but you the function/object you are working with has not finished.
Solutions in decreasing order of desirability:
Rework the code so that the vector using code is in it's own block/function/object so that it will be destroyed naturally
Use the swap trick, this way you don't have to worry about making sure that the vector is deallocated in all circumstances. It's lifetime will be tied to the object/function you are in.
new/delete the vector. This will free up a little bit more memory then the previous method but is also harder to make sure no memory is leaked.
The only technical difference between swapping and deleting is the base vector itself is not destroyed. This is a small overhead and is not worth worrying about (as long as you do eventually destroy the vector)
The larger consideration is which makes it easier to write correct code, and I believe swap wins over deleting there, but is worse then moving the vector somewhere else.
Don't use memory allocation functions unless you really need to. If your class needs a vector, always, just ad the std::vector member directly. No need to do memory allocation here.
In the cases where you need the dynamic vector, allocating and deleting it like in your first example is 100% correct.
In the second example, the call to std::swap is strictly spoken not needed, because the clear method will clear the vector, making it empty. One possible problem is that there is no guarantee that the vector will actually free the memory, giving it back to the operating system (or to the run time). The vector might keep the allocated memory just in case you will fill the vector right after clearing it. The call to std::swap may be a trick to 'force' the vector to free its internal data, but there is no guarantee that this will actually happen.
Delete deallocates the memory, the memory is then free for the next object but the vector has gone.
The 2nd trick frees any excess memory but leaves the vector intact, but empty.
Although both appear to work, I see no reason not to just call delete on the pointer. The vector should have a destructor that is called that will handle everything else.
If you just let the vector go out of scope, it will clean itself up appropriately with no extra work. If the vector is a member variable of a class, and you want it to deallocate its contents before its owner is destructed, then just call vec.clear().
If you want to keep the vector but deallocate the memory that holds its contents, then vec.swap(std::vector<int>()); will do that. There's no need to copy-construct the temporary into the original unless vec contains items that you want to keep and you just want to shrink the allocated memory down to something close to the current size().
This is not a valid comparison because the examples are dealing with different kinds of objects: dynamic duration and local duration. You can call the destructor OR use the swap trick (aka shrink_to_fit) with either one. The right way depends on whether you need the vector object to persist or not.
For example, you may need it to persist if there are references or pointers to it that must remain valid, in which case shrinking is the only way, regardless of how it was allocated.
I'm not sure why your second example uses a copy constructor for the temporary rather than a default constructor. That would save you the .clear() line of code.
You could make this generic for any object, even if it's not a container. I'm assuming here that std::swap is specialized to call vector::swap.
template<typename T>
void ResetToDefault(T & value)
{
std::swap(T(), value);
}
std::vector<int> vec;
//...
ResetToDefault(vec);
In the case that the vector really needs to be on the heap don't forget about:
std::auto_ptr<std::vector<int> > vec(new std::vector<int>);
especially useful with code like:
std::auto_ptr<std::vector<int> > vec(vectorFactoryFunction());