views:

554

answers:

11

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.

A: 

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.

Martin Beckett
+12  A: 

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.

JaredPar
Thanks, I'm aware of this though.
Jacob
@Jacob: Then why are you trying to do anything else? There's no need, nor is it ideomatic, to try to do anything to deallocate a vector.
Billy ONeal
@Billy: You're right, I can't think of a situation where I'd need anything else. I rewrote the code so the huge vector was used and dropped in a separate function
Jacob
Note you can only do this with std::vector because although the object is allocated on the stack the data is actually on the heap. std:: just handles the new/delete for you.
Martin Beckett
You don't necessarily need to move the code that uses the vector to another function. If you surround the code block where it's used with `{ ... }`, the destructor will be called at the end of that block.
Pedro d'Aquino
A: 

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.

Ben313
A: 

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().

Alan
A: 

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.

Patrick
+4  A: 
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();
caspin
`shrink_to_fit` is just a hint, actual shrinking is not guaranteed.
FredOverflow
The reason `shrink_to_fit` is a hint it to allow fancy stuff with memory. Shrinking to fit would be meaning less if the vector use something like small string optimization(unlikely), or if vectors always allocated from a pool and the smallest size was larger than your current vector size. It can be assumed however that `shrink_to_fit()` will make the vector as small as is reasonable.
caspin
A: 

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.

Cubbi
A: 

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);
Mark Ransom
`std::swap(T(), value)` won't compile in C++03 because `T()` is an rvalue and cannot be bound to a reference.
FredOverflow
A: 

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:

  1. Rework the code so that the vector using code is in it's own block/function/object so that it will be destroyed naturally
  2. 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.
  3. 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.

Winston Ewert
A: 

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.

Mike Seymour
A: 

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());
Graphics Noob