“Right” way to deallocate an std::vector object

2019-01-16 10:28发布

问题:

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.

回答1:

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.



回答2:

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.



回答3:

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


回答4:

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


回答5:

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.



回答6:

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.



回答7:

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.



回答8:

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.



回答9:

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



回答10:

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.



回答11:

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


回答12:

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