Új hozzászólás Aktív témák
-
dobragab
addikt
válasz
EQMontoya #3502 üzenetére
Csak elkészült ez a válasz, túl régóta írom.
Az emplace_back veszélyét szerintem az első világítja meg legjobban. Nem te hívod meg a konstruktort, így történhetnek olyan konverziók, amit nem szeretnénk.
A második példában az igazi körmös nem az emplace_back, hanem a RAII megsértéséért jár. Sőt, rosszabb: RAII és raw pointer keverése. Ugye resource acquisition is initialization lenne, csakhogy a foglalás után pakolod bele egy unique_ptr-be, itt épp implicit módon.
Ha azt vesszük, hogy a vector deklarációja zömmel három forrásfájllal és 2000 sorral arrébb van, mint ahol belepakolsz, és lehet, hogy rosszul emlékszel, hogy az most A*-ot, vagy unique_ptr<A>-t tartalmaz. push_back-nél ha rosszul emlékszel, a fordító hörögve kiszáll.
Szóval a második esetért közvetve az emplace_back felelős, közvetlenül az, aki nem emlékszik, hogy ott unique_ptr van. Általános esetben is, az emplace_back-nél nem mindig kell tudnod, hogy temporális vagy létező cuccot akarsz-e belerakni, és ez itt a fő veszélyforrás.
Engem kísértetiesen emlékeztet a kérdés a C-s NULL és a 0 esetére, a hatékonyságot kivéve. Mindenhova írhatsz 0-t, ahova NULL-t, de fordítva nem igaz. Most ne keverjük ide a printf-et, talán az az egy kivétel van. Mégis, az olvashatóság kedvéért pointereknél NULL-t, egészeknél 0-t írunk, pedig írhatnánk mindenhova 0-t. Ugyanígy, az olvashatóság kedvéért létező objektumnál tessék push_back-et írni, hogy biztosak lehessünk benne, ott tényleg létező objektumról van szó.
Ennyi indok bőven elég, hogy push_back helyett ne használjunk emplace_back-et.
Továbbmegyek: van egyáltalán létjogosultsága az emplace_back-nek?Ha egy már létező objektumot akarsz belepakolni, a kettő pont ugyanannyira hatékony, ugyanaz történik. Megnéztem, mi a helyzet abban az esetben is, amire az emplace_back elsődlegesen való: temporális objektumnál. Igazából arra ment ki a játék, hogy ilyenkor jobb-e az emplace_back, mint a push_back kiírt konstruktorhívással. Azért mégis csak jobban látni, hogy ott egy temporális objektumot pakolunk bele a vektorba, ha oda van írva.
Ilyenkor szoktam elővenni a Noisy osztályt, ami mindig kiírja, mikor mi történik vele, és számolja, hány példány van belőle, amúgy semmi másra nem jó. Itt a teljes forráskód, a Noisy túl hosszú ahhoz, hogy gátlástalanul bemásoljam, ide csak a lényeget hoztam.
int main()
{
std::vector<Noisy> vec;
vec.reserve (1000);
Noisy n1(1);
vec.emplace_back(n1);
Noisy n2(2);
vec.push_back(n2);
vec.emplace_back(Noisy(3));
vec.push_back (Noisy(4));
vec.emplace_back(5);
}Az elején azért van ott a ronda reserve, hogy ne legyen átméreteződés, az csak összezavar minket.
Az n1 és az n2 esetében kottára ugyanaz történik, ahogy el is várjuk, copy ctor. Noisy(3) és Noisy(4) is egyforma, move ctor. Az igazán érdekes a 4-es és 5-ös összehasonlítása. Annyit nyertünk az 5-össel a 4-eshez képest, hogy egy move ctorral és egy ki-move-olt objektum destruktorával kevesebb. Ezen spórolni meg igencsak barbár dolog C++11 óta.
Ha kikommenteled a move ctort, akkor a fordító sem generál - mert írtunk destruktort -, így a copy ctor hívódik, tehát a push_back lényegesen lassabb lesz.
És mivel az emplace_back eleve C++11, így jó eséllyel van move ctora a tárolt cuccnak. Akkor van igazán értelme az emplace_back-nek, ha nincs move ctor, ilyen-olyan okból. Nem is lehet neki jó move ctort írni - ilyet nehezen tudok elképzelni, de C++-ban semmit nem zárok ki -, vagy C++98-as, nem módosítható API-ból jön.
Ha nincs move ctor, a hatékonyság számít annyit, hogy szerintem elfogadható az emplace_back. Egyéb esetben én azt mondom, fordítva kéne: emplace_back helyett is push_back-et használni: fontosabb az, hogy lásd kiírva a ctort, mint a move ctor overhead-je.
Akkor viszont egy másik probléma jön elő: ha van move ctor, akkor push_back, ha nincs, emplace_back. Ez kb. ugyanolyan rossz, mint az eredeti probléma, szóval temporális objektumra egységesen kéne a kettő közül választani. Nézzük meg a várható kockázatokat és a nyereséget:
push_back: ha nincs move ctor, lassú, de jól olvasható és egyértelmű
emplace_back: ha nincs move ctor, gyorsabb, néhány karakterrel rövidebb. Várható kockázat: egy elrontott emplace_back miatt végtelen debuggolás...Szóval én azt mondom, temporális objektumnál az API függvényében kéne dönteni, hogy az adott projektben melyik. De létező objektumra egész biztosan push_back.
Új hozzászólás Aktív témák
● ha kódot szúrsz be, használd a PROGRAMKÓD formázási funkciót!
- AliExpress tapasztalatok
- Otthoni hálózat és internet megosztás
- ASUS routerek
- Luck Dragon: Asszociációs játék. :)
- Nagyrobogósok baráti topikja
- Szívós, szép és kitartó az új OnePlus óra
- Autós topik
- Milyen házat vegyek?
- Elektromos autók - motorok
- Samsung Galaxy S23 Ultra - non plus ultra
- További aktív témák...
- Lenovo ThinkPad P14s Ryzen 5 PRO5650u 32GB RAM 512GB SSD 4GB dedikált VGA Érintőkijelző
- Apple iPhone 15 Pro, 128Gb, független, fekete, 1 év garancia
- AMD Ryzen 5 5600X 6-Core 3.7GHz AM4
- Bomba ár! HP ProBook 430 G3 - i3-6GEN I 4GB I 128SSD I HDMI I 13,3" HD I Cam I W10 I Garancia!
- Bomba ár! HP ProBook 430 G5 - i3-7GEN I 4GB I 128GB SSD I HDMI I 13,3" FHD I Cam I W11 I Garancia!
- Bomba ár! HP Elite Dragonfly G1 - i5-8G I 16GB I 512SSD I 13,3" FHD Touch I Cam I W11 I Garancia!
- HIBÁTLAN iPhone 14 128GB Midnight -1 ÉV GARANCIA - Kártyafüggetlen, MS3093, 91% Akkumulátor
- Extra olcsó! HP 230 Vezetéknélküli USB-s Billentyűzet
- ÁRGARANCIA! Épített KomPhone i5 13400F 16/32/64GB RAM RTX 5060 8GB GAMER PC termékbeszámítással
- ÁRGARANCIA!Épített KomPhone i5 14600KF 32/64GB RAM RTX 5060Ti 16GB GAMER PC termékbeszámítással
Állásajánlatok
Cég: NetGo.hu Kft.
Város: Gödöllő
Cég: Promenade Publishing House Kft.
Város: Budapest