| Author |
HELP :: STL Vectors in VC7 - behaviour changed for clear() reserve() and capacity() ?
|
|
| Krishnan R.S. 2005-03-23, 4:01 am |
| Hello All,
I've got some code that used to work in VC6 but now asserts in VC7.
Code that used to work in VC6
---start snippet---
vector<int> my_vector;
/* setup some minimum amt of memory to allocate within the vector */
my_vector.reserve(10);
/* make sure there are no elems in the vector */
my_vector.clear();
assert( (my_vector.capacity() == 10) );
---end snippet---
Assuming that there are no memory exceptions my code above worked nicely in
VC6
With VC7 looks like the my_vector.clear() - clears the allocated/used
oprtion of the vector and also frees up the spare capacity we setup - i.e.
now capacity() returns me 0 with VC7 but used to be 10 with VC6.!!
I checked with the STL docs and this is not supposed to be the behaviour
......clear() only touches the used portions of the vector.
Anyone else seeing this behaviour in vc7 ?? Or am I doing something totally
wrong here ...
Thanks,
Krishnan
| |
| Carl Daniel [VC++ MVP] 2005-03-23, 4:01 am |
| Krishnan R.S. wrote:
> Hello All,
> I've got some code that used to work in VC6 but now asserts in VC7.
>
> Code that used to work in VC6
>
> ---start snippet---
> vector<int> my_vector;
>
> /* setup some minimum amt of memory to allocate within the vector */
> my_vector.reserve(10);
> /* make sure there are no elems in the vector */
> my_vector.clear();
>
> assert( (my_vector.capacity() == 10) );
>
> ---end snippet---
>
> Assuming that there are no memory exceptions my code above worked
> nicely in VC6
>
> With VC7 looks like the my_vector.clear() - clears the allocated/used
> oprtion of the vector and also frees up the spare capacity we setup -
> i.e. now capacity() returns me 0 with VC7 but used to be 10 with
> VC6.!!
>
> I checked with the STL docs and this is not supposed to be the
> behaviour .....clear() only touches the used portions of the vector.
>
> Anyone else seeing this behaviour in vc7 ?? Or am I doing something
> totally wrong here ...
Yes - you're relying on unspecified behavior.
std::vector<T>.clear() is defined to have a post condition of size()==0,
there's no guarantee that capacity() will have any particular value.
Logically, you could assume that it would either be 0 or the value that it
had before clear() was called, but neither of those is required.
If you want to erase all elements from a vector without changing capacity(),
you should use vec.erase(vec.begin(),vec.end()) instead of clear().
Note that clearing a vector right after default-constructing one (as in your
example above) is wasted effort - it's guaranteed to be empty on creation
unless you use one of the pre-filling constructors.
-cd
| |
| Krishnan R.S. 2005-03-23, 4:01 am |
| Hello Carl,
Ahhhh - somehow thought that clear was implemented as clear() { erase(
begin(), end() ); }
At least that's what I gathered from the often referenced SGI site ...
http://www.sgi.com/tech/stl/Vector.html
And
http://www.sgi.com/tech/stl/Sequence.html
If you look at clear() in the Sequence.htm link it essentially says that
clear() is an erase from begin() to end()
So calling erase() on the set of elems would not have changed much - or so
it seems ....
I guess that relying on clear() to remove only elems from the used part of
the vector was really non-standard!!
But they don't really say that capacity() will be affected in anyway - and
size() and capcity() were _meant_ to be different things!
But I'm glad to see that at least I'm not doing something that was
fundamentally wrong in vc7.
Thanks,
Krishnan
P.S.
====
Hmmmmm - vc7 yet to see some positive effects of this thing!!
--
"Krishnan R.S." <rskrishnan@hotmail.com> wrote in message
news:O5yvNI0LFHA.3616@TK2MSFTNGP09.phx.gbl...
> Hello All,
> I've got some code that used to work in VC6 but now asserts in VC7.
>
> Code that used to work in VC6
>
> ---start snippet---
> vector<int> my_vector;
>
> /* setup some minimum amt of memory to allocate within the vector */
> my_vector.reserve(10);
> /* make sure there are no elems in the vector */
> my_vector.clear();
>
> assert( (my_vector.capacity() == 10) );
>
> ---end snippet---
>
> Assuming that there are no memory exceptions my code above worked nicely
in
> VC6
>
> With VC7 looks like the my_vector.clear() - clears the allocated/used
> oprtion of the vector and also frees up the spare capacity we setup - i.e.
> now capacity() returns me 0 with VC7 but used to be 10 with VC6.!!
>
> I checked with the STL docs and this is not supposed to be the behaviour
> .....clear() only touches the used portions of the vector.
>
> Anyone else seeing this behaviour in vc7 ?? Or am I doing something
totally
> wrong here ...
>
> Thanks,
> Krishnan
>
>
>
>
| |
| Ken Alverson 2005-03-23, 4:01 pm |
| "Tom Widmer" <tom_usenet@hotmail.com> wrote in message
news:eL61tE5LFHA.3632@TK2MSFTNGP10.phx.gbl...
>
> I argued with the Dinkumware authors that this new behaviour was surprising
> to many users regardless of the exact wording of the standard, and they
> seemed to say that they would put it back the way it was before (e.g.
> clear() doesn't modify capacity()). Does anyone have a VC8 beta with which
> to confirm or deny this?
Judging by the number of times I've seen the "why doesn't my memory usage go
down when I call vector<>.clear(), the "old" behavior was surprising to many
users as well.
Ken
| |
| Carl Daniel [VC++ MVP] 2005-03-23, 4:01 pm |
| Tom Widmer wrote:
> I argued with the Dinkumware authors that this new behaviour was
> surprising to many users regardless of the exact wording of the
> standard, and they seemed to say that they would put it back the way
> it was before (e.g. clear() doesn't modify capacity()). Does anyone
> have a VC8 beta with which to confirm or deny this?
They did indeed put it back in VC8 - at least as of the Feb CTP.
-cd
| |
| Stephen Howe 2005-03-24, 4:00 am |
| > Well, the standard is not particularly well specified when it comes to the
> set of operations that can reduce the capacity of a vector.
And I regard that as deficiency with the standard.
Nothing wrong with VC6, VC7 or VC7.1 library in this regard.
Only the programmer knows from the code as to when any excess memory will no
longer needed.
There should be a shrink() function which miminises the amount of memory for
all standard containers (even things like deque as the array of pointers to
blocks of elements could be huge) rather than use things like the swap trick
which is non-binding on std::string. At that point the other member
functions can tightened as to so saying that excess memory won't be freed
(so it will be recycled in the event the programmer needs it for container
operations at a later point of execution).
Stephen Howe
| |
| Gene Bushuyev 2005-04-01, 4:03 pm |
| "Carl Daniel [VC++ MVP]" <cpdaniel_remove_this_and_nospam@mvps.org.nospam>
wrote in message news:%237ZL4N0LFHA.3760@TK2MSFTNGP12.phx.gbl...
....
>
> Yes - you're relying on unspecified behavior.
I don't think so. Though it wasn't spelled out explicitly, I think it's
clear that the standard intention was to keep the allocation created by
reserve until the next reallocation.
23.2.4.2/2
"After reserve(), capacity() is greater or equal to the argument of reserve
if reallocation happens; and equal to the previous value of capacity()
otherwise. Reallocation happens at this point if and only if the current
capacity is less than the argument of reserve()."
23.2.4.2/5
"It is guaranteed that no reallocation takes place during insertions that
happen after a call to reserve() until the time when an insertion would make
the size of the vector greater than the size specified in the most recent
call to reserve()."
>
> std::vector<T>.clear() is defined to have a post condition of size()==0,
> there's no guarantee that capacity() will have any particular value.
> Logically, you could assume that it would either be 0 or the value that it
> had before clear() was called, but neither of those is required.
>
> If you want to erase all elements from a vector without changing
capacity(),
> you should use vec.erase(vec.begin(),vec.end()) instead of clear().
clear() is equivalent to erase(begin(), end()). See Table 67 - Sequence
requirements in 23.1.1
Gene
| |
| Gene Bushuyev 2005-04-01, 9:00 pm |
| "Ken Alverson" <USENET.Ken@Alverson.net> wrote in message news:eL$F%
....
> Judging by the number of times I've seen the "why doesn't my memory usage
go
> down when I call vector<>.clear(), the "old" behavior was surprising to
many
> users as well.
Surprising only to those who didn't care to read Herb Sutter's books. A
standard idiom to clear the content of a container and release the memory is
swap operation: std::vector<T>().swap(myvector);
Gene
| |
| Ken Alverson 2005-04-01, 9:00 pm |
| "Gene Bushuyev" <gb@127.0.0.1> wrote in message
news:Vjh3e.5633$FN4.3828@newssvr21.news.prodigy.com...
>
> Surprising only to those who didn't care to read Herb Sutter's books. A
> standard idiom to clear the content of a container and release the memory is
> swap operation: std::vector<T>().swap(myvector);
As you say, that is an idiom - something that is peculiar and surprising to
people who aren't intimately familiar with the language. Also, one could
consider Herb's solution a guarantee to the letter of the law that the memory
will be freed. That (by itself) doesn't preclude clear() from also freeing
memory.
Ken
|
|
|
|