Does the standard ensure that the string :: erase and string :: pop_back DO NOT reallocate memory?

Does the standard guarantee that string::erase and string::pop_back DO NOT reallocate memory? After erasing some elements, is it possible that string can be automatically shortened?

I checked the standard, it says that string::erase and string::pop_back either throws std::out_of_range or throws nothing. Can I take this as a guarantee that these DO methods DO NOT perform any redistribution? Because redistribution can cause bad_alloc .

+7
c ++ string
source share
4 answers

No, sensible implementations may not be redistributed, but the standard does not guarantee that calls to these methods are not redistributed, the standard says about the requirements:

References, pointers, and iterators related to basic_string elements can be invalidated in the following ways: this basic_string object:

(4.1) as an argument to any standard library function referencing a non-const basic_string as an argument .227

(4.2) Calling non-constant member functions, except for the operator [], at, data, front, back, begin, rbegin, end and rend .

Both proposed methods belong to category 2 and, therefore, both can change capacity() , which would imply redistribution.

pop_back should have the same effect as erase , since erase is listed as:

Effects: defines the effective length xlen of the string, which should be removed as less than n and size() - pos . 3

The function then replaces the string controlled by *this with a string of length size() - xlen , whose first elements of pos are a copy of the initial elements of the original string controlled by *this , and the remaining elements of which are a copy of the original string controlled by *this , starting at pos + xlen .

There is no guarantee as to how this copy is made, so additional distributions or redistributions are possible.


Concerning

Can this be considered a guarantee that these methods do NOT redistribute? Since redistribution can cause bad_alloc .

The standard does not explicitly mention the bad_alloc feature bad_alloc by any of the methods. Even with reserve binding, this is not mentioned:

void reserve(size_type res_arg=0);

Throws: length_error if res_arg > max_size()

Thus, I do not think that this assumption can be made.

+3
source share

Yes, you can assume that The Throws: on these functions prohibits redistribution (which may cause bad_alloc ).

20.5.5.12 Exception Handling Restrictions [res.on.exception.handling]

Any of the functions defined in the C ++ standard library can report a failure by throwing an exception of the type described in its throws: a paragraph or a type obtained from the type specified in the throws: a paragraph that will be caught by the exception handler for the base type.

...

Functions defined in the C ++ standard library that do not have Outputs: a paragraph, but has a potentially striking specification of exceptions, can cause implementation-specific exceptions. 186 Implementations shall report errors of exclusion or exclusion from the standard exception classes (21.6.3.1, 21.8, 22.2).

Note that the specification does not explicitly say that something is marked "Throws: Nothing". can't give up anything. But at some point, common sense should prevail. The standard also does not explicitly state that these functions cannot reformat your disk. In general, the standard indicates what functions can do, and they are not allowed to do anything.

The only way a function throws an exception that is not specified in the type: spec (or a derived type) is if the client uses it in a way that causes undefined behavior.

+2
source share

Reading the documentation , I think it depends on the signature of the function. In the case of basic_string& erase(size_type pos = 0, size_type n = npos); it is described as a copy of the previous line. In the case of iterator erase(const_iterator first, const_iterator last); items deleted .

Actually, I am very surprised by the difference. I think you cannot be sure that there is no highlight.

EDIT Notice that in this small example, I keep the same address with every check:

 #include <iostream> int main() { std::string a; for(std::size_t i = 0; i < 10000; ++i) a += "Hello World ! My name is Bond... James Bond."; std::cout << (long)&a[0] << std::endl; a.erase(400000); std::cout << (long)&(a[0]) << std::endl; a.erase(10); std::cout << (long)&(a[0]) << std::endl; return 0; } 
+1
source share

I think this is guaranteed, even the standard does not speak explicitly about it. This describes the effect of redistribution on shrink_to_fit :

Notes: Reallocation invalidates all references, pointers, and iterators that refer to elements in the sequence, as well as to the iterator of the past end. If redistribution does not occur, they remain valid.

If redistribution occurs, all iterators, pointers, links will be invalidated. But erase and pop_back do not mention this; this means that they will not lead to the fact that all of them will be declared invalid, then redistribution will not occur.

+1
source share

All Articles