Um colega de trabalho queria escrever isso:
std::string_view strip_whitespace(std::string_view sv);
std::string line = "hello ";
line = strip_whitespace(line);
Eu disse que o retorno string_view
me deixava desconfortável a priori e, além disso, o apelido aqui parecia UB para mim.
Posso dizer com certeza que line = strip_whitespace(line)
, neste caso, é equivalente a line = std::string_view(line.data(), 5)
. Eu acredito que irá chamar string::operator=(const T&) [with T=string_view]
, que é definido para ser equivalente a line.assign(const T&) [with T=string_view]
, que é definido para ser equivalente a line.assign(line.data(), 5)
, que é definido para fazer isso:
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.
Mas isso não diz o que acontece quando existe um alias.
Ontem fiz esta pergunta no Slack cpplang e recebi respostas contraditórias. Procurando respostas super autoritativas aqui e / ou análise empírica das implementações de fornecedores de bibliotecas reais.
Eu escrevi casos de teste para string::assign
, vector::assign
, deque::assign
, list::assign
, e forward_list::assign
.
- O Libc ++ faz com que todos esses casos de teste funcionem.
- O Libstdc ++ faz com que todos funcionem, com exceção de
forward_list
, que segfaults. - Não conheço a biblioteca da MSVC.
O segfault no libstdc ++ me dá esperança de que este seja UB; mas também vejo o libc ++ e o libstdc ++ fazendo um grande esforço para fazer esse trabalho pelo menos nos casos mais comuns.
fonte
*this
. Mas não vejo nada para impedir a reutilização do armazenamento existente; nesse caso, isso se torna não especificado, uma vez que a semântica da substituição do armazenamento não é especificada.std::string::assign
caso e para o caso do contêiner (std::vector::assign
especificamente) .assign
requisitos em [tab: container.seq.req] .Respostas:
Exceto algumas exceções das quais a sua não é uma, chamar uma função de membro que não seja const (ou seja
assign
) em uma string invalida [...] ponteiros para seus elementos. Isso viola a pré-condição deassign
que[s, s + n)
é um intervalo válido, então este é um comportamento indefinido.Observe que o
string::operator=(string const&)
idioma é específico para tornar a auto-atribuição uma opção não operacional.fonte
assign
? Se sim, teríamos que definir um ponto específico dentro da implementação do assign para marcar quando exatamente a invalidação pode ocorrer, e acredito que isso não é algo que o C ++ faria. Eu poderia estar errado.std::vector::insert(iterator pos, const T& value)
deve funcionar sevalue
estiver no próprio vetor, porque o padrão não especifica que ele tem permissão para não funcionar, mesmo que essa referência possa ser invalidada pela chamada.