Zobrazit předchozí téma :: Zobrazit následující téma |
Autor |
Zpráva |
pcmaster
Založen: 28. 07. 2007 Příspěvky: 1821
|
Zaslal: 24. červen 2013, 15:45:19 Předmět: |
|
|
Ak ide o tento konkretny priklad, tak je to jedno. Ale predstav si namiesto "int" vlastnu triedu a v prvom pripade dojde ku kopirovaniu, co moze byt uplne katastrofalne.
Tak ci onak, ten prvy priklad je napicu a z najroznejsich dovodov by mali byt tie parametre opatrene aspon const. _________________ Off-topic flame-war addict since the very beginning. Registered since Oct. 2003!
Interproductum fimi omne est. |
|
Návrat nahoru |
|
|
rezna
Založen: 27. 07. 2007 Příspěvky: 2156
|
Zaslal: 24. červen 2013, 20:54:15 Předmět: |
|
|
pcmaster napsal: |
Ak ide o tento konkretny priklad, tak je to jedno. Ale predstav si namiesto "int" vlastnu triedu a v prvom pripade dojde ku kopirovaniu, co moze byt uplne katastrofalne.
Tak ci onak, ten prvy priklad je napicu a z najroznejsich dovodov by mali byt tie parametre opatrene aspon const. |
samozrejme ze kdyz tam je vlastni trida, ziskava to uplne jine rozmery apod.
ale Lemik to tu prave "rozhicoval" s intem a tak cekam jak to obhaji
jinak int a a const int a vyjde na stejno IMHO |
|
Návrat nahoru |
|
|
VladR
Založen: 30. 07. 2007 Příspěvky: 1322 Bydliště: Greater New York City Area
|
Zaslal: 24. červen 2013, 21:42:46 Předmět: |
|
|
Neviem kolko z vas pouzili exceptions v hlavnej renderovacej smycke, ale ja to mam v svojom C++ engine uz asi tak 8 rokov (a vtedy som kodil na hodne pomalej sunke) a nikdy som nezaregistroval pokles vykonu, dokonca ani pri terene, co renderoval v 3000 FPS.
A to tam nemam try/catch jeden ale tak zo 10 ich tam bude.
Niekolkokrat som si overil v release builde, ze vyremovanie exceptions neprida ani jeden jediny frame na vykone, takze ich nechavam zapnute cely cas pocas vyvoja, lebo uzasne ulahcuju debugovanie.
Teda, aspon ulahcovali, do doby nez som sa naucil pred ~8 rokmi pouzivat pointery spravne. Odvtedy sa pustili len zriedka, resp. ked som namiesto refaktoringu robil refucktoring (vtedy su fakt na nezaplatenie !)
Potom som presiel na C# / XNA a tam exceptions pre zmenu netreba fragmentovat vobec - pretoze staci jeden jediny try/catch na celu hru v hlavnej smycke v Program.cs a ten pekne vyhodi stacktrace, hoc aj 15 urovni dozadu, ze kde presne, na ktorom riadku a preco sa vynimka vyhodila).
Tento system nechavam aj v release builde, pretoze ked sa nieco poserie, tak netreba ziadne logy a podobne hovadiny. User proste postne screenshot a hned presne viem, co kde a preco sa posralo...
Bez exceptions ani ranu |
|
Návrat nahoru |
|
|
Lemik
Založen: 30. 07. 2007 Příspěvky: 138
|
Zaslal: 25. červen 2013, 04:47:38 Předmět: |
|
|
mar napsal: |
Lemik napsal: |
int add ( int value1, int value 2 )
namísto
int add( const int& value1, const int& value2 )
(a to dokonce i v knize o algoritmech...) |
Tak tohle není zrovna dobrý příklad. Elementární datové typy, co se vejdou do registru, nemá smysl předávat referencemi (pokud nejsou výstupní) - co je jednodušší, sečíst dvě hodnoty nebo dereferencovat dva ukazatele a sečíst výsledek? Samozřejmě za předpokladu, že to překladač nezoptimalizuje. U objektů je situace jiná, pointa byla vyhnout se kopírování objektů. |
rezna napsal: |
pcmaster napsal: |
Ak ide o tento konkretny priklad, tak je to jedno. Ale predstav si namiesto "int" vlastnu triedu a v prvom pripade dojde ku kopirovaniu, co moze byt uplne katastrofalne.
Tak ci onak, ten prvy priklad je napicu a z najroznejsich dovodov by mali byt tie parametre opatrene aspon const. |
samozrejme ze kdyz tam je vlastni trida, ziskava to uplne jine rozmery apod.
ale Lemik to tu prave "rozhicoval" s intem a tak cekam jak to obhaji
jinak int a a const int a vyjde na stejno IMHO |
Neobhájím. Spadám přesně do toho případu špatné výuky.
(Mohl bych ale takový příklad napsat, vysvětlit proč ho píšu takto a zmínit se proč to není moc vhodné.)
Předně - opravdu věřím, že rozhodnutí o tom jak s kódem naložit, mám přenechat překladači. Ví toho mnohem víc než já, psali ho lidi mnohem chytřejší a nadanější než já. Alespoň bych si tak měl přečíst manuál k překladači. A navíc překladače se stále vyvíjí, kdežto ten kód co napíši už s největší pravděpodobností přepisovat nebudu.
Co tedy int add( const int& value1, const int& value2 ) říká?
- že jsem nad příkladem moc nepřemýšlel
- hodnotu se snažím předat pomocí reference - nechci vytvořit v paměti místo, kam bych hodnotu zkopíroval, a používal ve funkci tuto novou hodnotu - dávám přednost používat hodnotu původní (a potenciálně jí i měnit)
- const říká, že ale tu hodnotu NESMÍM ve funkci změnit - a překladač to má (při překladu) ohlídat.
Mám rád pohled, kdy funkce je jako uživatel, kterému dám k dispozici pár hodnot jako parametry, ať si s nimi dělá co chce. Přitom mu určím podmínky:
- předávám Ti parametr(existující proměnnou) hodnotou = Dělej si s hodnotou co chceš... Nezáleží mi na tom, co s ní uděláš... Radši bych tě ani neměl nechat si hrát s původní hodnotou.
- předávám referencí = Dělej si s hodnotou co chceš, ale jsem zvědavý a předpokládám, že tu hodnotu změníš - a později si ji přečtu.
- předávám jako const = Můžeš číst, ale nechci, aby jsi jí měnil, sorry... U předání hodnotou to trošku ztrácí smysl (ale být C++ const by default, tak se o tom ani nebavíme)
- předání pointerem = Tady máš "černou díru", dělej si s ní co chceš... Já těď poběžím třeba tímhle směrem, no a kdyby něco, bylo mi ctí... A teď vážně: měl by jsi si zjistit, jestli ta adresa existuje (nullptr), pokud z ní hodláš číst (rozdíl oproti referenci, tam ti říkám, že ta adresa existuje).
-> Jestli chci, aby jsi ji vytvořil, že na ní někdy kouknu? Eeem... To bych asi chtěl, kdybych to dal jako návratovou hodnotu, ne jako parametr...
-> Jestli jí máš smazat? (zamyslí se nad int const* value) Eeem, proč Tě to tak moc vlastně zajímá? (pro jistotu se zamyslí nad const int* const value, nebo unique_ptr/shared_ptr)
Takže, když to shrnu, jde mi o to co tím kódem říkám. V C++ mám tuto možnost, takže když můžu, rád ji použiji - a spíše pro toho, co kód bude číst a možná používat, než kvůli kompileru.
Samozřejmě, že int a const int je v podstatě to samé (z hlediska toho, co chceš a co by překladač měl udělat), jde spíše o princip nebo o zvyk psaní. Pro člověka to může mít význam (třeba i ten, že chtěl napsat const int& a zapomněl, tak si toho jednou možná všimne, anebo ten co přijde po něm to napraví), pro překladač v tom rozdíl není.
const int& - někdo se usměje, co je to za blbost, kompiler prostě použije původní hodnotu a tuším ani neřeší že se jedná o referenci, což by řešil v případě ne-const reference, a někdo koukne a pochopí, že nejde o idiom "čekám, že tuto hodnotu změníš".
- Ano, používat unique_ptr kvůli int* je blbost. Kdo to udělá, je asi až trošku moc nejistý, cvok nebo tomu totálně nerozumí. Pointery bych rozhodně nezmiňoval pro začátečníky - reference by měli znát mnohem dříve než pointery - opět by to byl špatný příklad, ale chtěl jsem vysvětlit ten pohled. |
|
Návrat nahoru |
|
|
Weny Sky
Založen: 28. 07. 2007 Příspěvky: 241
|
Zaslal: 25. červen 2013, 08:15:27 Předmět: |
|
|
Lemik napsal: |
předání pointerem = Tady máš "černou díru", dělej si s ní co chceš... Já těď poběžím třeba tímhle směrem, no a kdyby něco, bylo mi ctí... A teď vážně: měl by jsi si zjistit, jestli ta adresa existuje (nullptr), pokud z ní hodláš číst (rozdíl oproti referenci, tam ti říkám, že ta adresa existuje) |
Obavam se, ze referenci mu predas NULL uplne setejne jako pres pointer. Vem si situaci, kdy predavas do funkce nejaky objekt, a predavas zrovna prvni objekt z dynamicky alokovaneho pole, ktere si ale zapomel alokovat :
kód: |
int *arr = 0;
add(arr[0], arr[1]);
|
Nehleda na to, ze pri pouziti pointeru nemusis vubec testovat jestli je NULL, protoze je to zbytecne. Kdyz to tam nekdo preda, tak to proste spadne a je to jeho problem. Max si v debug modu hlidat vstupni parametry assertama, ale tahat takovy balast do releasu. No nevim nevim.
Dalsim problemem u te funkce add je, ze kdyz budu chtit jako parametr predat vyraz, tak se zbytecne vytvori nejaka docasna promenna viz nasledujici kod:
kód: |
int xyz = 10;
int zyx = 11;
add(zyx + xyz, zyx + 20);
|
A s takovyma vecma ti vetsinou nepomuze ani optimalizer. Proste si to tak chtel, tak to tak mas. A ve vysledku budes mit nejpis pomalejsi kod. A kdyz ti to zoptimalizuje, tak do pouziti int add(int a, int b), takze je nesmysl neco takoveho pouzivat a spolehat na prekladac, kdyz je to od pohledu spatne |
|
Návrat nahoru |
|
|
OndraSej
Založen: 28. 07. 2007 Příspěvky: 765 Bydliště: Brandýs nad Labem
|
Zaslal: 25. červen 2013, 09:03:27 Předmět: |
|
|
Lemik napsal: |
Co tedy int add( const int& value1, const int& value2 ) říká?
- že jsem nad příkladem moc nepřemýšlel
- hodnotu se snažím předat pomocí reference - nechci vytvořit v paměti místo, kam bych hodnotu zkopíroval, a používal ve funkci tuto novou hodnotu - dávám přednost používat hodnotu původní (a potenciálně jí i měnit)
- const říká, že ale tu hodnotu NESMÍM ve funkci změnit - a překladač to má (při překladu) ohlídat. |
S prvním bodem souhlasím S druhým už ne - jak psal weny, může se ti stát, že překladač bude muset vytvořit dočasnou proměnnou s výsledkem, na kterou ti předá pointer. Ale i kdyby to dělat nemusel, tak na moderních počítačích je reference (pointer) větší nebo alespoň stejně velký jako int, takže místo v paměti tím spíš ztratíš.
Ale hlavně, "const int& X" říká, že X je reference na hodnotu, kterou TY nesmíš změnit. O tom, že X (nepřímo) nemůže změnit někdo jiný není řečeno ani slovo. Pro překladač to pak znamená, že X nemůže uložit do registru a musí pro něj sahat do paměti (což je ve srovnání se čtením z registru dost pomalé).
Lemik napsal: |
const int& - někdo se usměje, co je to za blbost, kompiler prostě použije původní hodnotu a tuším ani neřeší že se jedná o referenci, což by řešil v případě ne-const reference, a někdo koukne a pochopí, že nejde o idiom "čekám, že tuto hodnotu změníš". |
Spíš jde o idiom "neměň, ale čekej, že někdo jiný by mohl..."
Lemik napsal: |
Ano, používat unique_ptr kvůli int* je blbost. Kdo to udělá, je asi až trošku moc nejistý, cvok nebo tomu totálně nerozumí. Pointery bych rozhodně nezmiňoval pro začátečníky - reference by měli znát mnohem dříve než pointery - opět by to byl špatný příklad, ale chtěl jsem vysvětlit ten pohled. |
Reference je ukazatel, se všemi problémy, které z toho plynou. Vytvořit referenci inicializovanou jako null sice není tak triviální, ale mít referenci na smazaný objekt už není nic složitého. Proto mi dost vyhovuje třeba styl používaný v Google, kde se reference používají jen s const, jen pro složitější objekty a obvykle jen pro objekty, které volaná funkce po návratu už nebude používat. A na vše ostatní jsou pointery, protože u nich je na první pohled jasné, že se tam děje něco zvláštního. _________________ http://trionteam.net |
|
Návrat nahoru |
|
|
Krolli
Založen: 12. 05. 2013 Příspěvky: 13
|
Zaslal: 25. červen 2013, 20:06:03 Předmět: |
|
|
Lemik napsal: |
const int& - někdo se usměje, co je to za blbost, kompiler prostě použije původní hodnotu a tuším ani neřeší že se jedná o referenci, což by řešil v případě ne-const reference, a někdo koukne a pochopí, že nejde o idiom "čekám, že tuto hodnotu změníš".
|
Obávam sa, že prekladač pôvodnú hodnotu môže použiť maximálne v prípade, že danú funkciu inlinuje. Ak ale dojde k skutočnému volaniu, pôvodnú hodnotu použiť nemôže lebo nevie kde sa nachádza (pri každom volaní niekde inde, záleží na volajúcej funkcii) a nemôže ten int ani kopírovať, lebo by sa porušila vlastnosť referencie (hodnotu môže zmeniť niekto iný a prejaví sa to). Takže kompilátoru ostáva len predať na ňu pointer. Či to je pomalšie ako kopírovať primitívny typ je už otázne.
Možno som ale mimo a ľudia čo majú s prekladačmi a asm viac skúseností ako ja ma opravia. |
|
Návrat nahoru |
|
|
Tringi
Založen: 28. 07. 2007 Příspěvky: 289
|
Zaslal: 25. červen 2013, 20:14:03 Předmět: |
|
|
Pokud se to neprojeví na chování a výsledku tvého programu (nebo máš někde undefined behavior), může si překladač dělat (a taky že dělá) naprosto co chce. _________________ WWW | GitHub | TW |
|
Návrat nahoru |
|
|
mar
Založen: 16. 06. 2012 Příspěvky: 602
|
Zaslal: 25. červen 2013, 23:20:40 Předmět: |
|
|
Krolli napsal: |
Či to je pomalšie ako kopírovať primitívny typ je už otázne. |
Příklad: add(2,3):
int add( int x, int y ):
kód: |
mov eax, DWORD PTR _y$[esp-4]
mov ecx, DWORD PTR _x$[esp-4]
add eax, ecx
ret 0
|
int add( const int &x, const int &y ):
kód: |
mov eax, DWORD PTR _x$[esp-4]
mov eax, DWORD PTR [eax]
mov ecx, DWORD PTR _y$[esp-4]
add eax, DWORD PTR [ecx]
ret 0
|
volání:
kód: |
push 3
push 2
call _add
add esp,8
|
kód: |
sub esp, 8
lea eax, DWORD PTR $T0[esp+8]
push eax
lea ecx, DWORD PTR $T1[esp+12]
push ecx
mov DWORD PTR $T0[esp+16], 3
mov DWORD PTR $T1[esp+16], 2
call _add
add esp,16
|
Posuď sám (kód MSC 2008, 32-bit x86, max. optimalizace, bez whole program optimization, s omit stack frame, volání a implementace v jiných modulech) |
|
Návrat nahoru |
|
|
Ladis
Založen: 18. 09. 2007 Příspěvky: 1533 Bydliště: u Prahy
|
Zaslal: 26. červen 2013, 09:32:31 Předmět: |
|
|
A zkoušel sto v něčem jiném než 5 let starém MSC? _________________ Award-winning game developer
Naposledy upravil Ladis dne 26. červen 2013, 09:34:11, celkově upraveno 1 krát |
|
Návrat nahoru |
|
|
]semo[
Založen: 29. 07. 2007 Příspěvky: 1525 Bydliště: Telč
|
Zaslal: 26. červen 2013, 09:33:53 Předmět: |
|
|
A ty? :-) Myslíš, že se to nějak zásadně změnilo? _________________ Kdo jede na tygru, nesmí sesednout.
---
http://www.inventurakrajiny.cz/sipka/
Aquadelic GT, Mafia II, simulátory |
|
Návrat nahoru |
|
|
Ladis
Založen: 18. 09. 2007 Příspěvky: 1533 Bydliště: u Prahy
|
Zaslal: 26. červen 2013, 09:34:45 Předmět: |
|
|
V MSC asi ne, jako spousta věcí _________________ Award-winning game developer |
|
Návrat nahoru |
|
|
]semo[
Založen: 29. 07. 2007 Příspěvky: 1525 Bydliště: Telč
|
Zaslal: 26. červen 2013, 09:36:08 Předmět: |
|
|
No jo, asi nám začne flame, co? :-)..můžem pak ještě pokračovat s tématem Windows versus Linux :-). _________________ Kdo jede na tygru, nesmí sesednout.
---
http://www.inventurakrajiny.cz/sipka/
Aquadelic GT, Mafia II, simulátory |
|
Návrat nahoru |
|
|
Tringi
Založen: 28. 07. 2007 Příspěvky: 289
|
Zaslal: 26. červen 2013, 10:01:56 Předmět: |
|
|
Ladis: Kód, tak jak ho popsal (volání napříč unitami), lépe zkompilovat z principu nejde.
Reference se zde musí implementovat adresou, protože pořád je možnost, že side-effect něčeho dalšího změní hodnotu původní proměnné (a tedy i hodnotu která je vidět přes referenci) během provádění té funkce. _________________ WWW | GitHub | TW |
|
Návrat nahoru |
|
|
mar
Založen: 16. 06. 2012 Příspěvky: 602
|
Zaslal: 26. červen 2013, 10:02:43 Předmět: |
|
|
Pro Ladise: gcc 4.7.2 (rok starý) s AT&T syntaxí
rezervuje si zásobník, cleanup dělá až nakonec (MSC ale dělal něco podobného) - takže si tam ještě někde po volaní přidejte add esp, n
implementace:
kód: |
movl 8(%esp), %eax
addl 4(%esp), %eax
ret
|
kód: |
movl 4(%esp), %eax
movl (%eax), %eax
movl 8(%esp), %edx
addl (%edx), %eax
ret |
volání:
kód: |
movl $3, 4(%esp)
movl $2, (%esp)
call __Z3addii
|
kód: |
movl $3, 28(%esp)
movl $2, 24(%esp)
leal 28(%esp), %eax
movl %eax, 4(%esp)
leal 24(%esp), %eax
movl %eax, (%esp)
call __Z4addcRKiS0_
|
|
|
Návrat nahoru |
|
|
|