Un compañero de trabajo quería escribir esto:
std::string_view strip_whitespace(std::string_view sv);
std::string line = "hello ";
line = strip_whitespace(line);
Dije que regresar string_viewme inquietaba a priori y, además, el alias aquí me parecía UB.
Puedo decir con certeza que line = strip_whitespace(line)en este caso es equivalente a line = std::string_view(line.data(), 5). Creo que llamará string::operator=(const T&) [with T=string_view], que se define como equivalente a line.assign(const T&) [with T=string_view], que se define como equivalente a line.assign(line.data(), 5), que se define para hacer esto:
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.
Pero esto no dice qué sucede cuando hay alias.
Ayer hice esta pregunta en el cpplang Slack y obtuve respuestas mixtas. Buscando respuestas súper autorizadas aquí, y / o análisis empírico de implementaciones de vendedores de bibliotecas reales.
Escribí casos de prueba para string::assign, vector::assign, deque::assign, list::assign, y forward_list::assign.
- Libc ++ hace que todos estos casos de prueba funcionen.
- Libstdc ++ hace que todos funcionen, excepto que
forward_list, por defecto. - No sé sobre la biblioteca de MSVC.
La segfault en libstdc ++ me da la esperanza de que esto sea UB; pero también veo que tanto libc ++ como libstdc ++ están haciendo un gran esfuerzo para que esto funcione al menos en los casos comunes.
fuente

*this. Pero no veo nada para evitar que el almacenamiento existente se reutilice, en cuyo caso esto no se especifica, ya que la semántica de copiar el almacenamiento no está especificada.std::string::assigncaso y para el caso del contenedor (std::vector::assignespecíficamente) .assignrequisitos en [tab: container.seq.req] .Respuestas:
Salvo un par de excepciones de las cuales la suya no es una, llamar a una función miembro no constante (es decir
assign) en una cadena invalida [...] los punteros a sus elementos. Esto viola la condición previa deassignque[s, s + n)es un rango válido, por lo que este es un comportamiento indefinido.Tenga en cuenta que
string::operator=(string const&)tiene un lenguaje específico para hacer que la autoasignación no sea una operación.fuente
assign? En caso afirmativo, tendríamos que establecer un punto específico dentro de la implementación de asignar para marcar cuándo puede ocurrir exactamente la invalidación, y creo que eso no es algo que C ++ haría. Aunque podría estar equivocado.std::vector::insert(iterator pos, const T& value)debe funcionar sivalueestá dentro del vector, porque el estándar no especifica que está permitido no funcionar, aunque la referencia pueda invalidar esa referencia.