Коллега хотел написать это:
std::string_view strip_whitespace(std::string_view sv);
std::string line = "hello ";
line = strip_whitespace(line);
Я сказал, что возвращение string_view
сделало меня априори непростым , и, кроме того, псевдоним здесь выглядел как UB для меня.
Я могу с уверенностью сказать, что line = strip_whitespace(line)
в этом случае эквивалентно line = std::string_view(line.data(), 5)
. Я считаю, что вызов будет string::operator=(const T&) [with T=string_view]
, который определен, чтобы быть эквивалентным line.assign(const T&) [with T=string_view]
, который определен, чтобы быть эквивалентным line.assign(line.data(), 5)
, который определен для этого:
Preconditions: [s, s + n) is a valid range.
Effects: Replaces the string controlled by *this with a copy of the range [s, s + n).
Returns: *this.
Но это не говорит о том, что происходит, когда есть псевдоним.
Я задал этот вопрос вчера на cpplang Slack и получил смешанные ответы. Здесь вы найдете ответы на самые серьезные вопросы и / или эмпирический анализ реализаций реальных поставщиков библиотек.
Я написал тестовые случаи для string::assign
, vector::assign
, deque::assign
, list::assign
, и forward_list::assign
.
- Libc ++ заставляет все эти тестовые случаи работать.
- Libstdc ++ заставляет их все работать, за исключением
forward_list
, что segfaults. - Я не знаю о библиотеке MSVC.
Segfault в libstdc ++ дает мне надежду, что это UB; но я также вижу, что и libc ++, и libstdc ++ будут прилагать большие усилия, чтобы сделать это, по крайней мере, в обычных случаях.
источник
*this
. Но я ничего не вижу, чтобы предотвратить повторное использование существующего хранилища, и в этом случае это становится неопределенным, поскольку семантика перезаписи хранилища не определена.std::string::assign
случая и для случая контейнера (std::vector::assign
определенно) .assign
в [tab: container.seq.req] .Ответы:
Если исключить пару исключений, которые не являются вашими, вызов неконстантной функции-члена (т. Е.
assign
) В строке делает недействительными [...] указатели [...] на ее элементы. Это нарушает предварительное условие оassign
том , что[s, s + n)
это допустимый диапазон, так что это неопределенное поведение.Обратите внимание, что
string::operator=(string const&)
есть язык, специально предназначенный для самостоятельного назначения.источник
assign
? Если да, то мы должны были бы установить конкретную точку внутри реализации assign, чтобы пометить, когда именно может произойти аннулирование, и я считаю, что это не то, что C ++ сделает. Хотя я могу ошибаться.std::vector::insert(iterator pos, const T& value)
должна работать, еслиvalue
находится в самом векторе, потому что стандарт не указывает, что он разрешено не работать, даже если эта ссылка может быть аннулирована вызовом.