Współpracownik chciał to napisać:
std::string_view strip_whitespace(std::string_view sv);
std::string line = "hello ";
line = strip_whitespace(line);
Powiedziałem, że powrót string_view
sprawił, że poczułem niepokój a priori , a ponadto aliasing tutaj wyglądał dla mnie jak UB.
Mogę z całą pewnością stwierdzić, że line = strip_whitespace(line)
w tym przypadku jest to odpowiednik line = std::string_view(line.data(), 5)
. Wierzę, że zadzwoni string::operator=(const T&) [with T=string_view]
, która jest zdefiniowana jako równoważna line.assign(const T&) [with T=string_view]
, która jest zdefiniowana jako równoważna line.assign(line.data(), 5)
, która jest zdefiniowana w tym celu:
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.
Ale to nie mówi, co się stanie, gdy pojawi się aliasing.
Zadałem to pytanie wczoraj na cpplang Slack i otrzymałem mieszane odpowiedzi. Poszukuję tutaj autorytatywnych odpowiedzi i / lub analizy empirycznej implementacji prawdziwych dostawców bibliotek.
Pisałem przypadków testowych na string::assign
, vector::assign
, deque::assign
, list::assign
, i forward_list::assign
.
- Libc ++ sprawia, że wszystkie te przypadki testowe działają.
- Libstdc ++ sprawia, że wszystkie działają, z wyjątkiem tego
forward_list
, co segfault. - Nie wiem o bibliotece MSVC.
Segfault w libstdc ++ daje mi nadzieję, że jest to UB; ale widzę też, że zarówno libc ++, jak i libstdc ++ wkładają wiele wysiłku, aby to zadziałało przynajmniej w typowych przypadkach.
źródło
*this
. Ale nie widzę nic, co mogłoby uniemożliwić ponowne wykorzystanie istniejącej pamięci, w którym to przypadku nie jest to określone, ponieważ semantyka kopiowania pamięci nie jest określona.std::string::assign
skrzynki i skrzynki (std::vector::assign
szczególnie) .assign
w [tab: container.seq.req] .Odpowiedzi:
Pomijając kilka wyjątków, z których twój nie jest jeden, wywołanie funkcji non-const członka (tj.
assign
) W łańcuchu unieważnia [...] wskaźniki do jego elementów. To narusza warunek naassign
który[s, s + n)
jest ważny zakres, więc jest to niezdefiniowane zachowanie.Zauważ, że
string::operator=(string const&)
ma język specjalnie, aby samodzielne przypisywanie stało się niemożliwe.źródło
assign
? Jeśli tak, to musielibyśmy ustawić konkretny punkt w implementacji przypisania, aby zaznaczyć, kiedy dokładnie może nastąpić unieważnienie, i uważam, że to nie byłoby coś, co zrobiłby C ++. Mogę się jednak mylić.std::vector::insert(iterator pos, const T& value)
musi działać, jeślivalue
jest w samym wektorze, ponieważ standard nie określa tego może nie działać, nawet jeśli odwołanie może zostać unieważnione przez połączenie.