Ú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!
- Azonnali VGA-s kérdések órája
- Linux kezdőknek
- Véget vetne a hibrid magdizájnnak az Intel?
- Autós topik
- Samsung Galaxy S25 Ultra - titán keret, acélos teljesítmény
- Xiaomi 15 - kicsi telefon nagy energiával
- Fujifilm X
- Milyen monitort vegyek?
- E-roller topik
- LordAthis: Ismét egy "Idióta" A.I. Projekt, hogy meglovagolja a trendeket...
- További aktív témák...
- Szép! HP EliteBook 850 G8 Fémházas Multimédiás Laptop 15,6" -65% i7-1185G7 32/512 Iris Xe FHD EU/HUN
- Intel Xeon Gold 6146 / 12 mag / 24 szál / 24.75M Cache, 3.20 GHz / 4.20GHz Turbó / Beszámítás OK!
- Apple Macbook Air 2017 olcsón
- Vegyes SAS 400gb ssd-k, hibátlan szektorokkal. 1db új 960gb
- Honor Magic V5 -- 512Gb -- 16Gb Ram -- Magyar Nyelv -- EREDETI
- AZONNALI SZÁLLÍTÁSSAL Eladó Windows 8 / 8.1 Pro
- Fókusz, tér, élmény Dell U2913WM Ultrawide monitor
- ÁRGARANCIA! Épített KomPhone i5 14400F 16/32/64GB RAM RX 9060 XT 16GB GAMER PC termékbeszámítással
- Csere-Beszámítás! Akciós Gamer PC! R5 5500 / GTX 1070Ti Rog Strix / 32GB D4 / 500GB SSD
- ÁRGARANCIA!Épített KomPhone Ryzen 5 5600X 16/32/64GB RAM RTX 4060 8GB GAMER PC termékbeszámítással
Állásajánlatok
Cég: PCMENTOR SZERVIZ KFT.
Város: Budapest