Zastanawiam się, jakie są możliwe zalety kopiowania przy zapisie? Oczywiście nie oczekuję osobistych opinii, ale praktyczne scenariusze z rzeczywistego świata, w których może to być technicznie i praktycznie korzystne w namacalny sposób. A przez namacalny mam na myśli coś więcej niż oszczędzanie pisania &
postaci.
Aby wyjaśnić, to pytanie jest w kontekście typów danych, w których konstrukcja przypisania lub kopii tworzy niejawną płytką kopię, ale modyfikacje w niej tworzą niejawną głęboką kopię i stosuje do niej zmiany zamiast oryginalnego obiektu.
Powodem, dla którego pytam, jest to, że nie znajduję żadnych zalet posiadania COW jako domyślnego domyślnego zachowania. Używam Qt, który ma COW zaimplementowany dla wielu typów danych, praktycznie wszystkich, które mają jakieś dynamiczne przydzielanie pamięci. Ale jak to naprawdę wpływa na użytkownika?
Przykład:
QString s("some text");
QString s1 = s; // now both s and s1 internally use the same resource
qDebug() << s1; // const operation, nothing changes
s1[o] = z; // s1 "detaches" from s, allocates new storage and modifies first character
// s is still "some text"
Co wygrywamy, używając COW w tym przykładzie?
Jeśli wszystko, co zamierzamy zrobić, to użyć operacji const, s1
jest redundantne, może równie dobrze użyć s
.
Jeśli zamierzamy zmienić wartość, wówczas COW opóźnia kopię zasobu tylko do pierwszej operacji non-const, przy (choć minimalnym) koszcie zwiększenia liczby odwołań dla niejawnego udostępniania i odłączania od pamięci wspólnej. Wygląda na to, że cały koszt związany z COW jest bezcelowy.
Nie różni się zbytnio w kontekście przekazywania parametrów - jeśli nie zamierzasz modyfikować wartości, podaj jako const referen, jeśli chcesz zmodyfikować, albo wykonaj niejawną głęboką kopię, jeśli nie chcesz modyfikować oryginalny obiekt lub przekaż referencję, jeśli chcesz go zmodyfikować. Ponownie COW wydaje się niepotrzebnym narzutem, który niczego nie osiąga, i dodaje jedynie ograniczenie, że nie możesz modyfikować oryginalnej wartości, nawet jeśli chcesz, ponieważ każda zmiana odłączy się od oryginalnego obiektu.
Tak więc w zależności od tego, czy wiesz o COW, czy jesteś tego nieświadomy, może to skutkować kodem z niejasnym zamiarem i niepotrzebnym narzutem, lub całkowicie mylącym zachowaniem, które nie spełnia oczekiwań i powoduje, że drapiesz się po głowie.
Wydaje mi się, że istnieją bardziej wydajne i czytelniejsze rozwiązania, niezależnie od tego, czy chcesz uniknąć niepotrzebnej głębokiej kopii, czy zamierzasz ją wykonać. Więc gdzie jest praktyczna korzyść z COW? Zakładam, że musi to przynieść pewne korzyści, ponieważ jest wykorzystywany w tak popularnym i potężnym frameworku.
Co więcej, z tego, co przeczytałem, COW jest teraz wyraźnie zabronione w standardowej bibliotece C ++. Nie wiem, czy wady, które w nim widzę, mają coś z tym wspólnego, ale tak czy inaczej, musi być ku temu powód.
[]
operatora. Więc COW umożliwia zły projekt - nie brzmi to jak pożytek :) Punkt w ostatnim akapicie wydaje się słuszny, ale ja sam nie jestem wielkim fanem niejawnego zachowania - ludzie biorą to za pewnik, trudno jest ustalić, dlaczego kod nie działa zgodnie z oczekiwaniami, i zastanawiać się, dopóki nie wymyślą, co kryje się pod ukrytym zachowaniem.