Jaki jest prawidłowy sposób ponownego wykorzystania przeniesionego kontenera?
std::vector<int> container;
container.push_back(1);
auto container2 = std::move(container);
// ver1: Do nothing
//container2.clear(); // ver2: "Reset"
container = std::vector<int>() // ver3: Reinitialize
container.push_back(2);
assert(container.size() == 1 && container.front() == 2);
Z tego, co przeczytałem w wersji roboczej standardu C ++ 0x; ver3 wydaje się być poprawnym sposobem, ponieważ obiekt po przeniesieniu jest w formacie
„O ile nie określono inaczej, takie przeniesione przedmioty powinny być umieszczone w stanie ważnym, ale nieokreślonym”.
Nigdy nie znalazłem żadnego przypadku, w którym jest to „określone inaczej”.
Chociaż uważam, że ver3 jest nieco okrężna i miałbym znacznie preferowaną wersję ver1, chociaż vec3 może pozwolić na dodatkową optymalizację, ale z drugiej strony może łatwo prowadzić do błędów.
Czy moje założenie jest prawidłowe?
c++
c++11
move-semantics
ronag
źródło
źródło
clear
, ponieważ nie ma warunków wstępnych (a zatem nie ma zależności od stanu obiektu).std::vector
implementacja, która przechowała wskaźnik do swojego rozmiaru (wydaje się głupi, ale legalny). Przejście z tego wektora może pozostawić wskaźnik NULL, po czymclear
zakończy się niepowodzeniem.operator=
może również zawieść.Odpowiedzi:
Z sekcji 17.3.26 specyfikacji „stan ważny, ale nieokreślony”:
Dlatego obiekt jest pod napięciem. Możesz wykonać dowolną operację, która nie wymaga warunku wstępnego (chyba że najpierw zweryfikujesz warunek wstępny).
clear
na przykład nie ma żadnych warunków wstępnych. I przywróci obiekt do znanego stanu. Po prostu wyczyść go i używaj jak zwykle.źródło
clear
jest prawidłowe. 2) Gdy kontener znajdował się w nieokreślonym stanie, wywołanieclear
ustawia kontener w określonym stanie, ponieważ w standardzie obowiązują warunki końcowe (§ 23.2.3, tabela 100).std::vector<T>
ma niezmiennik klasy, którypush_back()
jest zawsze ważny (tak długo, jakT
jestCopyInsertable
).Obiekt jest w prawidłowym, ale niezdefiniowanym stanie zasadniczo oznacza, że chociaż dokładny stan obiektu nie jest gwarantowany, jest prawidłowy i jako takie funkcje składowe (lub funkcje niebędące funkcjami) gwarantują działanie, o ile nie polegają na na obiekcie o określonym stanie.
Funkcja
clear()
członkowska nie ma żadnych warunków wstępnych dotyczących stanu obiektu (poza tym, że jest poprawna, oczywiście) i dlatego może być wywoływana na obiektach przeniesionych. Z drugiej stronyfront()
zależy na przykład od tego, czy pojemnik nie jest pusty, a zatem nie można go wywołać, ponieważ nie ma gwarancji, że nie będzie pusty.Dlatego zarówno wersja 2, jak i wersja 3 powinny być w porządku.
źródło
front()
podano tylko dlastd::array
, a nawet ich nie ma w tabeli.front()
are*a.begin()
, §23.2.1 / 6 mówi „ Jeśli kontener jest pusty, tobegin() == end()
”, a § 24.2.1 / 5 mówi „ Biblioteka nigdy nie zakłada, że przeszłość- wartości końcowe można usunąć. ”. W związku z tym myślę, żefront()
można wywnioskować warunki wstępne , choć z pewnością można by to wyjaśnić.Nie sądzę, że możesz zrobić WSZYSTKO z przeniesionym obiektem (poza zniszczeniem go).
Czy nie możesz użyć
swap
zamiast tego, aby uzyskać wszystkie zalety przenoszenia, ale pozostawić pojemnik w znanym stanie?źródło
std::swap
ma 2 przypisania przenoszenia, z wartościami docelowymi tych przydziałów. To liczy się dla mnie jako „zrobienie czegoś z przeniesionym obiektem”