To je diskutabilní. Copy je bezpečné protože když někomu něco předáváš a neviš co s tím bude dělat tak mu radši dáš kopii. V js se předává kopie proměnné což je ukazatel na objekt a pak se člověk diví že mu voláný objekt změnil. (Tam je obrovský problém udělat kopii) Mně vyhovuje explicitně specifikovat move. Chaos ve std::function není ani tak chyba jazyka jako chyba špatného návrhu v stl. Těch tam máme víc. Začal bych třeba iostreamy
Move je v Rustu taky bezpečné, dělá to destructive move, tozn. původní objekt se zničí a interně je to implementované jako memcpy. Má to dost výhod, není potřeba psát kód pro move (což ušetří práci a nedá se v tom udělat chyba) a asi ani nejde vymyslet nic rychlejšího než memcpy, takže to má i vysoký výkon.
V C++ nebylo možné destructive move udělat ze dvou důvodů. První je, že C++ nemá borrow checker a tedy ani koncept objektu v moved stavu, který se už nesmí použít. Tohle by šlo simulovat něčím jako std::optional nebo nullptr, ale je těžké to nějak rozumně přidat vedle C++ copy sémantiky, aby se move jednoduše požívalo a dávalo to smysl. Druhý důvod, proč nešlo destructive move v C++ udělat, je ten, že v tomto konceptu nelze mít v objektu ukazatel/referenci na sama sebe (adresa se po move změní, dělá to memcpy) a přidání takového pravidla by zase rozbilo spoustu existujícího kódu.
To se mi na c++ líbí nejvíc že si mohu definovat co se při operaci přesunu skutečně děje. Navíc mohu zakázat kopírování a každýmu kdo bude chtít vytvořit kopii to vynadá hele nesmíš.
Já mluvil o bezpečnosti z hlediska organizace kódu a čitelnosti, ne z hlediska zabezpečení paměti. Chyby lze dělat i v jiné doméně než je pamět.
Obecně je v c++ vše hodnotou, bez ohledu na traits daného objektu. Pokud je to movable only object , musím explicitně povolit move
Koncept move, jak je implementovaný v C++, je už překonaný, není to dobré řešení. Když se v C++11 move přidávalo, tak to ale bohužel nešlo udělat lépe z důvodů, které jsem uvedl výše.
Destructive move je ve všem lepší, jak z hlediska výkonu, tak i organizace a přehlednosti kódu. Pro destructive move není třeba psát žádný kód, o všechno se postará automaticky překladač. Kód, který neexistuje, je z hlediska organizace a údržby nejlepší, není potřeba se jím vůbec zabývat.
Tohle je ale věc překladače a optimalizace.
Pokud překladač vidí kód destruktoru a vidí, že objekt má stav, který přeskakuje jeho skutečnou destrukci, může generovat kód tak, že vynechá destruktor úplně.
Pořád nějak rustaři neumí oddělit jazyk jako výrazový prostředek a finální kód.
Takže pokud někde použiju move nad std::unique_ptr, tak sic destruktor by se měl volat vždy, i když byl pointer přesunut, tak optimalizace překladače může zjistit, že destruktor se volá vždy s null pointerem a tedy destruktor v rámci optimalizace úplně vynechat (tedy nebude tam ani ten podmíněný skok). Blbý je, pokud k move došlo mimo aktuální scope, do kterého překladač nevidí.
To všechno se může dít bez nutnosti zavádět nový jazyk.
To vůbec není o Rustu nebo C++, ale o obecném designu move. Všimni si, že v mém předchozím příspěvku není o Rustu ani zmínka, s Rustem jsi začal ty.
Takže ještě jednou, destructive move, jako obecný design, má oproti move v C++ tyto zásadní výhody:
C++ překladač může někdy v okrajových případech nevolat destruktor, ale většinou se volá uživatelský kód move constructoru a pak ještě destructor, což je ztráta výkonu.
C++ komunita je si toho samozřejmě vědoma a existují návrhy, jak dostat destructive move do C++, tady je jeden z nich. Třeba se časem dočkáme destructive move i v C++.
Intenzivně se zabývám programováním zejména v jazyce C++. Vyvíjím vlastní knihovny, vzory, techniky, používám šablony, to vše proto, aby se mi usnadnil život při návrhu aplikací. Pracoval jsem jako programátor ve společnosti Seznam.cz. Nyní jsem se usadil v jednom startupu, kde vyvíjím serverové komponenty a informační systémy v C++
Přečteno 53 737×
Přečteno 25 575×
Přečteno 23 821×
Přečteno 22 329×
Přečteno 22 270×