Я использую идиому удаления C++ и сталкиваюсь со странной проблемой. Если я получаю доступ к элементу, используя строковый индекс, результат не такой, как ожидалось.
string str = "A man, a plan, a canal: Panama";
str.erase(remove(str.begin(), str.end(), str[1]), str.end());
Результат: Аман, план, канал: Панаа
и если я использую, как показано ниже, результат будет таким, как ожидалось.
string str = "A man, a plan, a canal: Panama";
str.erase(remove(str.begin(), str.end(), ' '), str.end());
Результат: Аман, аплан, аканал: Панама
Посмотрите на подпись std::remove
:
template< class ForwardIt, class T >
ForwardIt remove( ForwardIt first, ForwardIt last, const T& value );
value
передается по константной ссылке, поэтому после удаления первого пробела ваш str[1]
указывает на неправильную память. Небезопасно получать доступ к элементам контейнера во время изменения контейнера.
@ Томас Хорошая идея; Я предпочитаю второй подход. Я вижу, что у Влада тоже есть аккуратная (хотя и немного непонятная) альтернатива.
Алгоритм std::remove
объявляется следующим образом
template<class ForwardIterator, class T>
ForwardIterator remove(
ForwardIterator first, ForwardIterator last,
const T& value // <-- reference!
);
Как видите, третий параметр объявлен как ссылка const T& value
.
Итак, в этом вызове
str.erase(remove(str.begin(), str.end(), str[1]), str.end());
третий аргумент — ссылка на объект str[1]
, значение которого меняется в алгоритме на букву 'm'
при встрече с первым символом ' '
.
Если бы вы написали, например
str.erase(remove(str.begin(), str.end(), str[1] + 0), str.end());
вы получите ожидаемый результат, потому что в этом случае ссылка относится к временному объекту.
И решение состоит в том, чтобы заранее передать
static_cast<char>(str[1])
или присвоитьstr[1]
переменной типаchar
.