Un collègue voulait écrire ceci:
std::string_view strip_whitespace(std::string_view sv);
std::string line = "hello ";
line = strip_whitespace(line);
J'ai dit que le retour string_view
me mettait mal à l'aise a priori , et en plus, le pseudonyme ici me semblait UB.
Je peux dire avec certitude que line = strip_whitespace(line)
dans ce cas est équivalent à line = std::string_view(line.data(), 5)
. Je crois que va appeler string::operator=(const T&) [with T=string_view]
, qui est défini pour être équivalent à line.assign(const T&) [with T=string_view]
, qui est défini pour être équivalent à line.assign(line.data(), 5)
, qui est défini pour faire ceci:
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.
Mais cela ne dit pas ce qui se passe quand il y a un alias.
J'ai posé cette question sur le cpplang Slack hier et j'ai obtenu des réponses mitigées. Vous recherchez ici des réponses faisant autorité et / ou une analyse empirique des implémentations de fournisseurs de bibliothèques réelles.
J'ai écrit des cas de test pour string::assign
, vector::assign
, deque::assign
, list::assign
et forward_list::assign
.
- Libc ++ fait fonctionner tous ces cas de test.
- Libstdc ++ les fait tous fonctionner sauf pour
forward_list
, qui segfaults. - Je ne connais pas la bibliothèque de MSVC.
Le segfault dans libstdc ++ me donne l'espoir que c'est UB; mais je vois aussi à la fois libc ++ et libstdc ++ faire de gros efforts pour que cela fonctionne au moins dans les cas courants.
la source
*this
. Mais je ne vois rien pour empêcher la réutilisation du stockage existant, auquel cas cela devient non spécifié, car la sémantique de la copie du stockage n'est pas spécifiée.std::string::assign
boîtier et pour le conteneur (std::vector::assign
spécifiquement) .assign
exigences de [tab: container.seq.req] .Réponses:
Sauf quelques exceptions dont la vôtre n'est pas une, appeler une fonction membre non const (c'est-à-dire
assign
) sur une chaîne invalide [...] les pointeurs vers ses éléments. Cela constitue une violation de la condition sine qua non à c'est une plage valide, donc ce comportement est indéfini.assign
[s, s + n)
Notez que le
string::operator=(string const&)
langage a spécifiquement pour faire de l'auto-affectation un no-op.la source
assign
? Si oui, alors nous devrons définir un point spécifique dans l'implémentation de l'attribut pour marquer quand exactement l'invalidation peut se produire, et je crois que ce n'est pas quelque chose que C ++ ferait. Je pourrais toutefois avoir tord.std::vector::insert(iterator pos, const T& value)
doit fonctionner s'il sevalue
trouve dans le vecteur lui-même, car la norme ne spécifie pas qu'il est autorisé à ne pas fonctionner, même si cette référence peut être invalidée par l'appel.