I had a C++ string that I wanted to truncate. Say, something like this:
void remove_extension(std::string& s)
{
auto pos = s.rfind('.');
if (pos != std::string::npos) {
s.resize(pos);
}
}
The question is whether this function can throw an exception. Can the call to resize throw an exception when used to make a string smaller?
And the answer appears to be yes, at least in C++17.
The specification of the resize(n) method in C++17 says that in the case where n <= size(), “the function replaces the string designated by *this with a string of length n whose elements are a copy of the initial elements of the original string designated by *this.”
In other words, the resize(n) method, when shrinking a string (or leaving the size unchanged), behaves as if a new string is created, which replaces the current string. And creating a new string may throw bad_alloc.
Of course, implementations may use the as-if rule and resize the string in place, but the standard does not require them to do so.
But wait, all is not lost. Because another way to shrink a string is to use the erase(n) method.
- [basic.string]:
basic_stringis a contiguous container. - [container.requirements.general] (11): Unless otherwise specified…, all container types defined in this Clause meet the following additional requirements:
- [container.requirements.general] (11.3): No
erase()… function throws an exception. - [string.erase]: Throws:
length_errorifn > max_size().
There are a few things referenced in the “…” portion of [container.requirements.general] (11), but they do not apply to basic_string.
Hooray, we can use the erase method to shrink the string and avoid an exception.
void remove_extension(std::string& s)
{
auto pos = s.rfind('.');
if (pos != std::string::npos) {
s.erase(pos);
}
}
Bonus chatter: It appears that the issue of resize() throwing an exception when trimming was brought up¹ by Stephan T. Lavavej and fixed by Tim Song in P1148R0: Starting in C++20, if you call the resize() method to shrink the string (or keep it the same size), the behavior is defined in terms of erasure and therefore does not throw an exception.
¹ I could have written “raised” but I didn’t.²
² Except that I just did.
0 comments