[v3] basic_string::reserve() shrink-to-fit?

Neil Ferguson nferguso@eso.org
Thu Dec 11 14:51:00 GMT 2003


Hi, all -

I just tried the following bit of code on GCC 3.3, and the libstdc++
that comes with it:

--

#include <iostream>
#include <string>

using namespace std;

int main()
{
     string str;

     cout << endl;
     cout << "Version of libstdc++:   " << __GLIBCPP__ << endl;
     cout << endl;

     cout << "Initial capacity:       " << str.capacity() << endl;

     str = "Wibble";
     cout << "After 6 char assign:    " << str.capacity() << endl;

     str.reserve(1000000);
     cout << "After reserve(1000000): " << str.capacity() << endl;

     str.reserve();
     cout << "After reserve():        " << str.capacity() << endl;

     cout << endl;
}


--

and got this output:

--

Version of libstdc++:   20030513

Initial capacity:       0
After 6 char assign:    6
After reserve(1000000): 1003491
After reserve():        1003491

--

ie. reserve() doesn't seem to shrink the string capacity to fit. On
examining basic_string::reserve() in basic_string.tcc:

--

   template<typename _CharT, typename _Traits, typename _Alloc>
     void
     basic_string<_CharT, _Traits, _Alloc>::reserve(size_type __res)
     {
       if (__res > this->capacity() || _M_rep()->_M_is_shared())
         {
           if (__res > this->max_size())
             __throw_length_error("basic_string::reserve");
           // Make sure we don't shrink below the current size
           if (__res < this->size())
             __res = this->size();
           allocator_type __a = get_allocator();
           _CharT* __tmp = _M_rep()->_M_clone(__a, __res - this->size());
           _M_rep()->_M_dispose(__a);
           _M_data(__tmp);
         }
     }

--

the only way I can see for a shrink-to-fit to occur is if more than one
string refers to the same data storage, ie. _M_rep()->_M_is_shared() is
true.

Apart from the library version, the same thing happens with GCC 3.3.2.
I haven't tried the CVS version, but the reserve() code is the same.

With this modified code:

--

   template<typename _CharT, typename _Traits, typename _Alloc>
     void
     basic_string<_CharT, _Traits, _Alloc>::reserve(size_type __res)
     {
 >>    if (__res != this->capacity() || _M_rep()->_M_is_shared())
         {
           if (__res > this->max_size())
             __throw_length_error("basic_string::reserve");
           // Make sure we don't shrink below the current size
           if (__res < this->size())
             __res = this->size();
           allocator_type __a = get_allocator();
           _CharT* __tmp = _M_rep()->_M_clone(__a, __res - this->size());
           _M_rep()->_M_dispose(__a);
           _M_data(__tmp);
         }
     }

--

so that __res only needs to be different from capacity(), rather than
greater, I get the following output:

--

Version of libstdc++:   20031016

Initial capacity:       0
After 6 char assign:    6
After reserve(1000000): 1003491
After reserve():        6

--

and a shrink-to-fit has occurred.

I'd be grateful for comments on the sensibility (or otherwise) of my
change to the reserve() method.

Thanks,
Neil.



More information about the Libstdc++ mailing list