C ++ string using allocated max buffer?

Declare a variable string s;

and do s = "abc"; now it has a 3 character buffer.

After

s = "abcd" has a 4 character buffer.

Now after the third statement

s = "ab" question is whether the buffer will retain 4 characters or reallocate the buffer with 2 characters?

If it allocates 2 character buffers, I can say that it should keep the allocated buffer.

Does it keep a buffer of maximum size?

 s = "ab" s="abc" s="a" s="abcd" s="b" 

It should now contain a buffer of size 4.

Is it possible?

+6
source share
3 answers

s = "ab" the question is, will it contain a 4-word buffer or will it redistribute a 2-word buffer?

It does not redistribute the buffer. I don’t know if the standard mentioned, but all implementations that I have ever seen cause redistribution only if they need to increase capacity. Never shrink. Even if you have a string with 4 characters and call .resize(2) or .reserve(2) , the capacity will not change. To make the string (or containers) reallocate the memory according to the exact size, there is a simple swap trick for this

 s.swap(string(s)); 

What's going on here? You create a temporary one from s that will have its capacity exactly equal to s.size() , then replace it with the original string. A temporary destructor will release all necessary resources.

Again, I am not saying that this is standard, but all the implementations I have seen have this behavior.

+7
source

The string will save its buffer after allocating it and only redistribute it if it needs an even larger buffer. It will also probably start with an initial buffer size greater than 3 or 4.

You can check the allocated size using the capacity() member function.


After James comments below, I still believe that my answer is correct for the examples given in the question.

However, for a reference counted implementation, a sequence similar to this

 s = "some rather long string..."; std::string t = "b"; s = t; 

would set s.capacity() to t.capacity() if the implementation decides to exchange an internal buffer between s and t .

+10
source

You can easily see the behavior of your implementation by calling std::string::capacity at different times. In general, I would be surprised if any implementation ever had a three-character buffer. (Not words, but bytes, at least on most modern machines.) In practice, implementations differ and also vary depending on how the new length occurs: with g ++, for example, deleting characters using std::string::erase will not reduce the capacity of the row, but assigning a new, smaller row. VC ++ does not reduce capacity in any case. (In general, VC ++ and g ++ have very different strategies for managing memory in strings.)

EDIT:

Given other answers (which do not even correspond to the usual practice): here is a small test program that I used to check my statements above (although I really did not need this for g ++ - I know that the internals of the implementation are pretty good):

 #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; } 

Give it a try. The results are very instructive.

0
source

Source: https://habr.com/ru/post/893772/


All Articles