Why doesn't vector::clear remove elements from a vector?

Solution 1:

You have no right to get a segmentation fault. For that matter, a segmentation fault isn't even part of C++. Your program is removing all elements from the vector, and you're illegally accessing the container out of bounds. This is undefined behaviour, which means anything can happen. And indeed, something happened.

Solution 2:

When you access outside of the bounds of a vector, you get Undefined Behavior. That means anything can happen. Anything.

So you could get the old value, garbage, or a seg-fault. You can't depend on anything.

If you want bounds checking, use the at() member function instead of operator []. It will throw an exception instead of invoking Undefined Behavior.

Solution 3:

From cppreference:

void clear();

Removes all elements from the container. Invalidates any references, pointers, or iterators referring to contained elements. May invalidate any past-the-end iterators. Many implementations will not release allocated memory after a call to clear(), effectively leaving the capacity of the vector unchanged.

So the reason there is no apparent problem is because the vector still has the memory available in store. Of course this is merely implementation-specific, but not a bug. Besides, as the other answers point out, your program also does have Undefined Behavior for accessing the cleared contents in the first place, so technically anything can happen.

Solution 4:

Let's imagine you're rich (perhaps you are or you aren't ... whatsoever)!

Since you're rich you buy a piece of land on Moorea (Windward Islands, French Polynesia). You're very certain it is a nice property so you build a villa on that island and you live there. Your villa has a pool, a tennis court, a big garage and even more nice stuff.

After some time you leave Moorea since you think it's getting really boring. A lot of sports but few people. You sell your land and villa and decide to move somewhere else.

If you come back some time later you may encounter a lot of different things but you cannot be certain about even one of them.

  • Your villa may be gone, replaced by a club hotel.
  • Your villa may be still there.
  • The island may be sunken.
  • ...

Who knows? Eventhough the villa may not longer belong to you, you might even be able to jump in the pool or play tennis again. There may also be another villa next to it where you can swim in an even bigger pool with nobody distracting you.

You have no guarantee of what you're gong to discover if you come back again and that's the same with your vector which contains three pointers in the implementations I've looked at: (The names may be different but the function is mostly the same.)

  • begin points to the start of the allocated memory location (i.e. X)
  • end which points to the end of the allocated memory +1 (i.e. begin+4)
  • last which points to the last element in the container +1 (i.e. begin+4)

By calling clear the container may well destroy all elements and reset last = begin;. The function size() will most likely return last-begin; and so you'll observe a container size of 0. Nevertheless, begin may still be valid and there may still be memory allocated (end may still be begin+4). You can even still observe values you set before clear().

std::vector<int> a(4);
a[2] = 12;
cout << "a cap " << a.capacity() << ", ptr is " << a.data() << ", val 2 is " << a[2] << endl;
a.clear();
cout << "a cap " << a.capacity() << ", ptr is " << a.data() << ", val 2 is " << a[2] << endl;

Prints:

a cap 4, ptr is 00746570, val 2 is 12
a cap 4, ptr is 00746570, val 2 is 12

Why don't you observe any errors? It is because std::vector<T>::operator[] does not perform any out-of-boundary checks (in contrast to std::vector<T>::at() which does). Since C++ doesn't contain "segfaults" your program seems to operate properly.

Note: On MSVC 2012 operator[] performs boundary checks if compiled in the debug mode.

Welcome to the land of undefined behaviour! Things may or may not happen. You probably can't even be cartain about a single circumstance. You can take a risk and be bold enough to take a look into it but that is probably not the way to produce reliable code.

Solution 5:

The operator[] is efficient but comes at a price: it does not perform boundary checking.

There are safer yet efficient way to access a vector, like iterators and so on.

If you need a vector for random access (i.e. not always sequential), either be very careful on how you write your programs, or use the less efficient at(), which in the same conditions would have thrown an exception.