Is std::string guaranteed not to give back memory spontaneously?
Is it guaranteed by the standard that std::string will not give back allocated memory spontaneously if reassigned from a string of a smaller size?
In other words:
std::string str = "Some quite long string, which needs a lot of memory";
str = "";
str = "A new quite long but smaller string"; // Guaranteed to not result in a heap allocation?
I ask because i'm depending on this to avoid heap fragmentation.
No guarantee whatsoever.
[string.cons]/36 defines assigning a const char* to an std::string in term of a move-assignment, whose definition is:
[string.cons]/32
basic_string& operator=(basic_string&& str) noexcept(/*...*/)
Effects: Move assigns as a sequence container, except that iterators, pointers and references may be invalidated.
This shows that the Committee let the implementation choose freely between an invalidating operation and a more conservative one.
CPP reference states that assignment to a pointer-to-char
Replaces the contents with those of null-terminated character string pointed to by s as if by *this = basic_string(s), which involves a call to Traits::length(s).
This "as if" actually boils down to an rvalue assignment, so the following scenario is quite possible:
A fresh temporary string is created.
This string steals its contents as via assignment to an rvalue reference.
If your strings are short (up to 15 or 22 bytes, depending on the compiler/std lib) and you are using a relatively recent compiler in C++11 or later mode, then you are likely to benefit from the Short String Optimization (SSO). In this case the string contents are not separately allocated on the heap.
This link also contains a lot of details on common implementations and allocation strategies.
However, both of the strings in your example are too long for SSO.
In other words:
std::string str = "Some quite long string, which needs a lot of memory";
str = "";
str = "A new quite long but smaller string"; // Guaranteed to not result in a heap allocation?
I ask because i'm depending on this to avoid heap fragmentation.
No guarantee whatsoever.
[string.cons]/36 defines assigning a const char* to an std::string in term of a move-assignment, whose definition is:
[string.cons]/32
basic_string& operator=(basic_string&& str) noexcept(/*...*/)
Effects: Move assigns as a sequence container, except that iterators, pointers and references may be invalidated.
This shows that the Committee let the implementation choose freely between an invalidating operation and a more conservative one.
CPP reference states that assignment to a pointer-to-char
Replaces the contents with those of null-terminated character string pointed to by s as if by *this = basic_string(s), which involves a call to Traits::length(s).
This "as if" actually boils down to an rvalue assignment, so the following scenario is quite possible:
A fresh temporary string is created.
This string steals its contents as via assignment to an rvalue reference.
If your strings are short (up to 15 or 22 bytes, depending on the compiler/std lib) and you are using a relatively recent compiler in C++11 or later mode, then you are likely to benefit from the Short String Optimization (SSO). In this case the string contents are not separately allocated on the heap.
This link also contains a lot of details on common implementations and allocation strategies.
However, both of the strings in your example are too long for SSO.
Comments
Post a Comment