resize and clear of vector

T

toton

Hi,
I am using a vector to reserve certain amount of memory, and reuse
it for new set of data, to avoid reallocation of memory.
so the call is something like
vector<my_data> v;///the temporary storage.
v.reserve(300); ///at max I have 300 data.

now, my_data doesn't have a default ctor (as it doesn't have a default
state).

to use vector v again and again,
I am doing ,
v.resize(0);
////and then use it. I can do v.clear() for better.
Now the questions are,
1) do clear zero's capacity , i.e frees memory? (Then I can't use it,
as it iteration the vector will reallocate memory)
2) do resize to a size smaller than existing size reduces capacity
(Then resize(0) will also do the same thing )
3) do a resize with a size smaller than existing size requires
default (or any other ctor ) ?

thanks
 
J

Juha Nieminen

toton said:
1) do clear zero's capacity , i.e frees memory?

No. std::vector never frees memory (except when it's destroyed,
of course).
2) do resize to a size smaller than existing size reduces capacity

No.

If you want to free the memory taken by a std::vector, there's
a known trick for that:

{
std::vector<my_data> tmp;
v.swap(tmp);
}
// Here 'v' will have 0 size and will have no memory allocated

Note that the curly brackets are very relevant there.
 
M

Michael DOUBEZ

toton a écrit :
Hi,
I am using a vector to reserve certain amount of memory, and reuse
it for new set of data, to avoid reallocation of memory.
so the call is something like
vector<my_data> v;///the temporary storage.
v.reserve(300); ///at max I have 300 data.

now, my_data doesn't have a default ctor (as it doesn't have a default
state).

to use vector v again and again,
I am doing ,
v.resize(0);
////and then use it. I can do v.clear() for better.
Now the questions are,
1) do clear zero's capacity , i.e frees memory? (Then I can't use it,
as it iteration the vector will reallocate memory)
It is not required by the standard thus AFAIK existing implementations
don't.
2) do resize to a size smaller than existing size reduces capacity
(Then resize(0) will also do the same thing )
It is not required by the standard thus AFAIK existing implementations
don't.
3) do a resize with a size smaller than existing size requires
default (or any other ctor ) ?
No reason it should.

The usual trick to release memory of a vector is:
vector<myClass> my_vector(100000);

//clear by swapping with empty vector
std::vector<myClass>().swap(my_vector);


Michael
 
M

Michael DOUBEZ

toton a écrit :
Hi,
I am using a vector to reserve certain amount of memory, and reuse
it for new set of data, to avoid reallocation of memory.
so the call is something like
vector<my_data> v;///the temporary storage.
v.reserve(300); ///at max I have 300 data.

now, my_data doesn't have a default ctor (as it doesn't have a default
state).
[snip]
3) do a resize with a size smaller than existing size requires
default (or any other ctor ) ?

I don't understand your concern about default constructor.

std::vector doesn't require a default constructor. You can pass the
object to use for construction as second parameter.

vector<my_data> v(10,my_data(42);

The same is true of resize:
v.resize(72,my_data(36);

Michael
 
T

toton

No. std::vector never frees memory (except when it's destroyed,
of course).


No.

If you want to free the memory taken by a std::vector, there's
a known trick for that:

{
std::vector<my_data> tmp;
v.swap(tmp);
}
// Here 'v' will have 0 size and will have no memory allocated

Note that the curly brackets are very relevant there.

Thanks,
The trick works.
But, as I am not interested to release memory (except destructor of
course ) , as your post says clear doesn't release memory.
However , from this code it gives output ,
vector<int> vi(10) ;
cout<<"sz "<<vi.size()<<" cap "<<vi.capacity()<<endl; (size &
capacity 10, as expected)
std::generate(vi.begin(),vi.end(),rand);
cout<<endl; for_each(vi.begin(),vi.end(),cout<<_1<<" ");
cout<<"sz "<<vi.size()<<" cap "<<vi.capacity()<<endl; (size &
capacity 10, as expected)
vi.clear();
cout<<"sz "<<vi.size()<<" cap "<<vi.capacity()<<endl; (size &
capacity 0, I expected size = 0 while capacity 10)
However the statement vi.resize(0); makes size 0 , capacity 10.
so, as I don't want to release memory except destructor ,
1) which never releases memory resize(0) or clear() ?
2) the capacity is giving a wrong result ?
3) result of clear (and/or) resize whether to release memory is
implementation dependent ?
I am using Visual Studio 7.1 with MS implementation of std lib.

thanks
abir
 
R

Rolf Magnus

Michael said:
It is not required by the standard thus AFAIK existing implementations
don't.

Actually, the standard requires that this is not done.
It is not required by the standard thus AFAIK existing implementations
don't.

Actually, the standard requires that this is not done.
 
T

toton

Actually, the standard requires that this is not done.


Actually, the standard requires that this is not done.

When I go through the MS implementation (VS 7.1 ) of STL, clear looks
like,
void clear()
{ // erase all
_Tidy();
}
void _Tidy()
{ // free all storage
if (_Myfirst != 0)
{ // something to free, destroy and deallocate it
_Destroy(_Myfirst, _Mylast);
this->_Alval.deallocate(_Myfirst, _Myend - _Myfirst);///check this
line. it deallocates
}
_Myfirst = 0, _Mylast = 0, _Myend = 0;
}
Thus it removes memory (deallocates) not only destroys. That is why
capacity comes as 0 after clear. However it is not same for resize(0),
where it doesn't call deallocate (only construct or destroy) .
The results are given in my previous post.
Is it wrong according to std ? or just implementation defined ?
Thus which of the two (clear / resize(0) ) NEVER releases memory
according to std , if any one of them do at all.

thanks
abir
 
R

Rolf Magnus

toton said:
When I go through the MS implementation (VS 7.1 ) of STL, clear looks
like,
void clear()
{// erase all
_Tidy();
}
void _Tidy()
{// free all storage
if (_Myfirst != 0)
{ // something to free, destroy and deallocate it
_Destroy(_Myfirst, _Mylast);
this->_Alval.deallocate(_Myfirst, _Myend - _Myfirst);///check this
line. it deallocates
}
_Myfirst = 0, _Mylast = 0, _Myend = 0;
}

Seems to be a violation of the C++ standard.
Thus it removes memory (deallocates) not only destroys. That is why
capacity comes as 0 after clear. However it is not same for resize(0),
where it doesn't call deallocate (only construct or destroy) .
The results are given in my previous post.
Is it wrong according to std ? or just implementation defined ?

The C++ standard says that for any sequence a, a.clear() should do the
equivalent to a.erase(a.begin(), a.end()). The description of the effects
of std::vector::erase doesn't mention any change in capacity/reallocation.
Thus which of the two (clear / resize(0) ) NEVER releases memory
according to std , if any one of them do at all.

The standard says that the behavior of resize() if the new size is less than
the old one is equivalent to the corresponding erase() call. Since that's
also the case for clear(), both must have exactly the same result in a
conforming implementation.
 
M

Michael DOUBEZ

Rolf Magnus a écrit :
Actually, the standard requires that this is not done.


Actually, the standard requires that this is not done.

I could not find the relevant requirement in the standard.
Can you or anyone provide it ?

Michael
 
S

Stephen Howe

Actually, the standard requires that this is not done.

Where? The standard is silent on this. The standard is inadeqate.
Seems to be a violation of the C++ standard.

No. The standard neither forbids nor blesses the practice.
Therefore it is implementation defined.
The standard says that the behavior of resize() if the new size is less
than
the old one is equivalent to the corresponding erase() call. Since that's
also the case for clear(), both must have exactly the same result in a
conforming implementation.

Yes. Which does not say anything about what happens to the memory.

Stephen Howe
 
S

Stephen Howe

Actually, the standard requires that this is not done.
I could not find the relevant requirement in the standard.
Can you or anyone provide it ?

He is incorrect. It is not there.
The standard is _silent_ on what happens to memory and that means it is
implementation defined.

Stephen Howe
 
R

Rolf Magnus

Stephen Howe said:
Where? The standard is silent on this. The standard is inadeqate.

It gives information about the effects that erase() has, and re-allocation
is not one of those, so it doesn't happen. Invalidation of iterators to the
erased elements and those after it is an effect, but invalidation of those
before is not. A re-allocation would invalidate all iterators, so it can't
happen.
What makes you believe it's optional?
Yes. Which does not say anything about what happens to the memory.

It says that the implementation the OP is using is non-conforming, because
the behavor of resize(0) is different from that of clear().
 
P

P.J. Plauger

It gives information about the effects that erase() has, and re-allocation
is not one of those, so it doesn't happen. Invalidation of iterators to
the
erased elements and those after it is an effect, but invalidation of those
before is not. A re-allocation would invalidate all iterators, so it can't
happen.
What makes you believe it's optional?


It says that the implementation the OP is using is non-conforming, because
the behavor of resize(0) is different from that of clear().

Actually, it says nothing of the sort. But there was a Defect Report
asking for clarification, and the Library Working Group chose to
clarify the matter by ruling that the library can't reduce the
capacity on a clear. That ruling came down after VC++ V7.1 froze,
but you'll find the now "correct" behavior in VC++ V8.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
R

Rolf Magnus

P.J. Plauger said:
Actually, it says nothing of the sort.

Table 67 says that the effect of clear() for sequences is the same as
erase(begin(), end()), and 23.2.4.2 says that resize(sz) has the same
effect as:

if (sz > size())
insert(end(), sz-size(), c);
else if (sz < size())
erase(begin()+sz, end());
else
; // do nothing


so doesn't that mean that clear() has the same effect as resize(0)?
 
P

P.J. Plauger

Table 67 says that the effect of clear() for sequences is the same as
erase(begin(), end()), and 23.2.4.2 says that resize(sz) has the same
effect as:

if (sz > size())
insert(end(), sz-size(), c);
else if (sz < size())
erase(begin()+sz, end());
else
; // do nothing


so doesn't that mean that clear() has the same effect as resize(0)?

The issue in question was whether, under any circumstances, vector
could reduce capacity. The C++ Standard just didn't say. The LWG,
after some discussion, determined that clear should not reduce
capacity (even though it doesn't explicitly say that it can't) but
swap should (even though it doesn't explicitly say that it can).
IOW, the current rule is an *interpretation* of what should be
desired behavior.

Many years ago, I had several requests from customers for some way
to reduce the capacity of a vector. Absent clear guidance from the
C++ Standard, I picked a way and those customers were happy. When
the LWG made a different rule, the Dinkumware library changed to
match the new rule. You can persist all you want in asserting that
the answer is obvious in hindsight, but we did have to guess.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
R

Rolf Magnus

P.J. Plauger said:
The issue in question was whether, under any circumstances, vector
could reduce capacity.

We had two issues here. The second one is if resize(0) may behave
differently than clear(), and C++98 explicitly says that this is not
allowed.
The C++ Standard just didn't say.

I was assuming that it's enough that a reallocation is not mentioned as an
effect of erase(). It could have been more explicit though.
The LWG, after some discussion, determined that clear should not reduce
capacity (even though it doesn't explicitly say that it can't) but swap
should (even though it doesn't explicitly say that it can).

The 98 version of the standard (the only one available to me ATM) forbids
that. Was it changed in the 03 version?
IOW, the current rule is an *interpretation* of what should be desired
behavior.

I really hate it if a standard must be interpreted.
 
B

Bo Persson

Rolf Magnus wrote:
:: P.J. Plauger wrote:
::
::: :::
:::
::: The issue in question was whether, under any circumstances, vector
::: could reduce capacity.
::
:: We had two issues here. The second one is if resize(0) may behave
:: differently than clear(), and C++98 explicitly says that this is not
:: allowed.
::
::: The C++ Standard just didn't say.
::
:: I was assuming that it's enough that a reallocation is not mentioned
:: as an effect of erase(). It could have been more explicit though.
::
::: The LWG, after some discussion, determined that clear should not
::: reduce capacity (even though it doesn't explicitly say that it
::: can't) but swap should (even though it doesn't explicitly say that
::: it can).
::
:: The 98 version of the standard (the only one available to me ATM)
:: forbids that. Was it changed in the 03 version?
::
::: IOW, the current rule is an *interpretation* of what should be
::: desired behavior.
::
:: I really hate it if a standard must be interpreted.

It is not really an interpretation, but a clarification. :)

From what I understand, the original question was about the standard saying
that after a call to reserve(x), the capacity can never go below x. But what
if reserve() is never called, can the capacity shrink then?

And the clarification is: No!


The only sort-of-exception is swap, which sort of reduces the capacity, but
can also be seen as only transferring it elsewhere.



Bo Persson
 
R

Rolf Magnus

Bo said:
Rolf Magnus wrote:
:: P.J. Plauger wrote:
::
::: :::
:::
::: The issue in question was whether, under any circumstances, vector
::: could reduce capacity.
::
:: We had two issues here. The second one is if resize(0) may behave
:: differently than clear(), and C++98 explicitly says that this is not
:: allowed.
::
::: The C++ Standard just didn't say.
::
:: I was assuming that it's enough that a reallocation is not mentioned
:: as an effect of erase(). It could have been more explicit though.
::
::: The LWG, after some discussion, determined that clear should not
::: reduce capacity (even though it doesn't explicitly say that it
::: can't) but swap should (even though it doesn't explicitly say that
::: it can).
::
:: The 98 version of the standard (the only one available to me ATM)
:: forbids that. Was it changed in the 03 version?
::
::: IOW, the current rule is an *interpretation* of what should be
::: desired behavior.
::
:: I really hate it if a standard must be interpreted.

It is not really an interpretation, but a clarification. :)

Well, if there are different views, it's an interpretation.
From what I understand, the original question was about the standard
saying that after a call to reserve(x), the capacity can never go below x.
But what if reserve() is never called, can the capacity shrink then?

And the clarification is: No!

My impression was that swap() was guaranteed to reduce the capacity and
everything else was guaranteed not to. I thought that was absolutely clear,
considering that I read something like that quite often here and elsewhere.
I'm not so sure now, since there seem to be different opinions, and the
standard is not really fully clear about it.
The only sort-of-exception is swap, which sort of reduces the capacity,
but can also be seen as only transferring it elsewhere.

Actually, I didn't find anything in the standard that says so, but maybe I
just missed it. Could you give chapter/verse?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,772
Messages
2,569,593
Members
45,111
Latest member
VetaMcRae
Top