This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

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


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.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]