tags:

views:

283

answers:

6
+10  Q: 

C++ vector::clear

vector <weight> decoy;

void clear_decoy() {  

    decoy.clear();   

    vector<weight> (decoy).swap(decoy);  
}

In the above method clear_decoy(), what does vector<weight> (decoy).swap(decoy); mean please?

Does the method clear decoy or not? Thanks!

+1  A: 

With clear,

All the elements of the vector are dropped: their destructors are called, and then they are removed from the vector container, leaving the container with a size of 0.

Swap just swaps the two vectors,

Swap content

Exchanges the content of the vector by the content of vec, which is another vector of the same type. Sizes may differ.

After the call to this member function, the elements in this container are those which were in vec before the call, and the elements of vec are those which were in this. All iterators, references and pointers remain valid for the swapped vectors.

It seems you are swapping nothing really and just restores to default allocation. Clear can deallocate but it sometimes does not. You are not only reducing the size but lessening the space allocated with the swap statement.

0A0D
is the memory released?
ladyfafa
@ladyfafa: With the swap statement, the amount of space allocated is reduced. That is the nice part of vectors.
0A0D
@0A0D, i see, thanks!!
ladyfafa
+6  A: 

clear removes all entries from the vector, but may not necessarily deallocate the space. This swap idiom restores the vector to having no space allocated.

Fred Larson
Actually `clear` *can* deallocate the space the vector occupies. But it does not *have* to. It usually does not in most STL implementations though.
Billy ONeal
@Billy ONeal: Thanks. I edited my answer.
Fred Larson
@Fred: +1 for edit.
Billy ONeal
+11  A: 

It creates a new vector of Weight objects (which will be empty) and swaps it with decoy.

The reason for this is that by default, std::vector<t>::clear often doesn't actually reduce the storage used by a vector, it merely destroys all the objects contained there. This way, the vector has room to store more objects without reallocation in the future.

Sometimes, however, you want to trim the capacity in the vector. Swapping with a newly created vector (which lives until the end of it's line, and is therefore destroyed there) frees all the memory allocated by the vector.

Billy ONeal
Oh dear! My darling C++, you make trouble for those who love you by being smarter than we are.
Vulcan Eager
Being smart have a social cost.
Klaim
This is very C++y. C++ exposes memory management here so you have the chance to customize things for your needs. By default C++ tries to be as fast as it can, and so if you don't follow this code you're going to get faster code. In cases where you have a very large vector and you remove many of its elements then you can use this idiom to free resources to the OS, on the expense of speed. Usually you don't want to do that (i.e., don't fix what's not broken).
wilhelmtell
+15  A: 

I've never seen that form before.

I have seen it written as:

vector<weight>().swap(decoy);

Which means "create a new empty vector, and swap it with the existing one.

vector<weight> (decoy).swap(decoy);

To understand that, break in to parts.

vector<weight>(decoy) create a new vector (with it's contents copied from the now empty decoy). The new vector is an anonomous temporary, so let's pretent it's name is newvector.

newVector.swap(decoy); swaps the new vector with decopy.

(Updated per comments to fix bug)

James Curran
+1 for suggesting a better (and more) common construction of the same thing.
Billy ONeal
That has to be `vector<weight>().swap(decoy)`. You can call member functions on temporaries, but you can't pass them as non-const reference arguments.
Mike Seymour
+1 I'm a bad typist. :)
John Dibling
I think C++0x STL definition adds a `shrink` method to reduce the memory footprint based on the actual size... or is this wishful thinking ?
Matthieu M.
@Matthieu: yes, it's called `shrink_to_fit`, but the implementation doesn't have to honour it.
Mike Seymour
Well, the implementation doesn't have to reduce the capacity to 0 even for an empty vector either. They could even apply the small string optimization to the vector class too, I just thought worth mentioning it :)
Matthieu M.
+8  A: 

That code is a failed attempt to use a common trick to ensure the memory allocated by the vector is freed. It may or may not actually do that, depending on whether or not the vector's copy constructor allocates memory to match the other vector's size, or its capacity.

To reliably free the memory, use the following:

void clear_decoy() {  
    vector<weight>().swap(decoy);  
}

This creates a temporary empty vector (with little or no memory allocated), swaps this with decoy so that the memory is now owned by the temporary, then destroys the temporary, freeing the memory.

Mike Seymour
Excellent point.
John Dibling
While this is true, no sane STL implementation is going to allocate based on capacity here.
Billy ONeal
@Billy: Indeed; the clumsy clear-copy-swap dance is very likely to work, but the simpler version is guaranteed to work.
Mike Seymour
+3  A: 

As 0A0D mentions, the effect of swap is to exchange the underlying controlled memory between the two vectors. But this warrants a little more explanation.

When you clear a vector, the elements are removed from it at least as far as the programmer is concerned. size() becomes zero and capacity() may or may not change. But the Standard doesn't guarantee that the memory used by the vector will actually be returned back to the operating system. So if you had 1000 elements in the vector before the clear() and each took 1000 bytes memory, after the clear() each element's destructor is called, but the vector may still be holding on to a 1,000,000 byte allocation.

This is sometimes undesirable. The 'swap trick' you note above has the effect of exchanging the controlled memory between the two vectors. Hence decoy ends up with it's controlled memory reset.

Here is what is happening step-by-step:

  1. decoy elements are each erased. The elements' destructors are called, and the vector's size() becomes zero. The actual memory may not be deallocated.
  2. A new vector is constructed on the stack (vector<weight> (decoy)) and the elements from decoy are copied in to it. Since decoy was just clear()ed, no elements are copied in to the temporary vector. However, see edit below. You don't know that the controlled memory is not swapped.
  3. The temporary vector's and decoy's memory are swapped (.swap(decoy);) resulting in decoy being both cleared and it's memory transferred to the temporary.
  4. The temporary falls off the stack, resulting in it's memory being deallocated.

This is referred to as "the swap trick".

EDIT: As Mike mentions, the original programmer is doing it wrong. The temporary should not be constructed based on decoy, it should just be default constructed. You don't know for sure that swap() will only copy the elements and not the controlled memory underneath.

John Dibling
+1 Great explanation
0A0D