C++ string uses maximum buffer allocated?
I declare a variable string s;
and do s = "abc";
now it has buffer of 3 characters.
After
s = "abcd"
it has a buffer of 4 characters.
Now after the third 开发者_StackOverflow社区statement
s = "ab"
question is will it keep the buffer of 4 characters or will it reallocate a 2 character buffer?
If it will allocate 2 character buffer is there any way I can tell it to keep the allocated maximum buffer.
So does it keep the buffer of maximum size ever allocated ?
s = "ab"
s="abc"
s="a"
s="abcd"
s="b"
Now it should keep a buffer of size 4.
Is that possible?
The string will keep its buffer once it is allocated, and only reallocate if its needs an even larger buffer. It will also likely start with an initial buffer size larger than 3 or 4.
You can check the allocated size using the capacity()
member function.
After James' comments below I still believe my answer is correct for the examples given in the question.
However, for a reference counted implementation a sequence like this
s = "some rather long string...";
std::string t = "b";
s = t;
would set s.capacity()
to be equal to t.capacity()
if the implementation decides to share the internal buffer between s
and t
.
s = "ab" question is will it keep buffer of 4 words or will it reallocate 2 word buffer ?
It will not reallocate the buffer. I don't know if it's mentioned in the standard, but all the implementations I have ever seen issue a reallocation only if they need to increase the capacity. Never to decrease. Even if you have a string with 4 characters and call .resize(2)
or .reserve(2)
the capacity will not change. In order to force the string (or containers) to reallocate memory to fit the exact size, there's a simple swap
trick for that
s.swap(string(s));
What happens here? You create a temporary from s which will have its capacity exactly equal to s.size()
then swap it with your original string. The destructor of the temporary will free all the necessary resources.
Again, I am not claiming this is standard, but all the implementations I've seen have this behavior.
You can easily see the behavior of your implementation by calling
std::string::capacity
at various times. In general, I'd be surprised
if any implementation ever had a buffer of three characters. (Not
words, but bytes, at least on most modern machines.) In practice,
implementations vary, and also vary depending on how the new length
comes about: with g++, for example, removing characters with
std::string::erase
will not reduce the capacity of the string, but
assigning a new, smaller string will. VC++ doesn't reduce the capacity
in either case. (In general, VC++ and g++ have very different
strategies with regards to memory management in strings.)
EDIT:
Given the other responses (which don't even correspond to usual practice): here's the small test program I used to verify my statements above (although I really didn't need it for g++—I know the internals of the implementation quite well):
#include <string>
#include <iostream>
#include <iomanip>
template<typename Traits>
void
test()
{
std::string s;
size_t lastSeen = -1;
std::cout << Traits::name() << ": Ascending:" << std::endl;
while ( s.size() < 150 ) {
if ( s.capacity() != lastSeen ) {
std::cout << " " << std::setw( 3 ) << s.size()
<< ": " << std::setw( 3 ) << s.capacity() << std::endl;
lastSeen = s.capacity();
}
Traits::grow( s );
}
std::cout << Traits::name() << ": Descending: " << std::endl;
while ( s.size() != 0 ) {
Traits::shrink( s );
if ( s.capacity() != lastSeen ) {
std::cout << " " << std::setw( 3 ) << s.size()
<< ": " << std::setw( 3 ) << s.capacity() << std::endl;
lastSeen = s.capacity();
}
}
std::cout << "Final: capacity = " << s.capacity() << std::endl;
}
struct Append
{
static void grow( std::string& s )
{
s += 'x';
}
static void shrink( std::string& s )
{
s.erase( s.end() - 1 );
}
static std::string name()
{
return "Append";
}
};
struct Assign
{
static void grow( std::string& s )
{
s = std::string( s.size() + 1, 'x' );
}
static void shrink( std::string& s )
{
s = std::string( s.size() - 1, 'x' );
}
static std::string name()
{
return "Assign";
}
};
int
main()
{
test<Append>();
test<Assign>();
return 0;
}
Try it. The results are quite instructive.
精彩评论