Avatar
petr.dar
Člen
Avatar
petr.dar:

Zdař všichni, při programování jsem narazil na problém:
Teoreticky: Potřebuju přesunout hodnotu ukazatele z A do B.
když napíšu B = A tak to nestačí, protože A můžu změnit, smazat v B pak nebudu mít nic.
tak to zkoušim vyřešit přes

#include <cstring>
void * memmove ( void * destination, const void * source, size_t num );

Ale jakou hodnotu mám napsat místo num, když přesouvám vlastní třídy? Jak se zjistí velikost třídy?
Ď

 
Odpovědět 14. června 4:31
Avatar
martanec
Člen
Avatar
Odpovídá na petr.dar
martanec:

ako sucet velkosti atributov(memberov) danej triedy

 
Nahoru Odpovědět 14. června 7:56
Avatar
Odpovídá na petr.dar
Luboš Běhounek (Satik):

k zjištění velikosti můžeš použít operátor sizeof

Nahoru Odpovědět  +2 14. června 8:43
:)
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na petr.dar
Martin Dráb:

Přesouvat třídy pomocí memmove není zrovna nejdoporučovanější řešení, zejména když obsahují ukazatele. Pokud chceš do proměnné b dostat kopii třídy z proměnné a (obě třeba typu C *), tak v C++ k tomuto účelu slouží kopírovací konstruktor:

b = new C(*a);

Samozřejmě, pokud přesunutí v paměti pro danou třídu znamená více než kopírování, musíš kopírovací konstruktor předefinovat.

Nahoru Odpovědět  +2 14. června 8:49
2 + 2 = 5 for extremely large values of 2
Avatar
petr.dar
Člen
Avatar
Odpovídá na Martin Dráb
petr.dar:

No vždycky jsem se kopírovacím konstruktorům snažil vyhýbat velkým obloukem, ale teď mi asi nic jinýho nezbyde. memmove byl blbost, tam se ty ukazatele nepoužívají. Tak aspoň něco.
Ale baví mě sledovat jak v odpovědích maji rádcové každý jiný názor a styl programování, většinou bohužel - víc jak půlka píšou špatné, nebo neůplné odpovědi.
Ď :-)

 
Nahoru Odpovědět 15. června 15:28
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na petr.dar
Taskkill:

Kopírující konstruktor není zase taková věda, jsem si docela jistej, že jamile mu přijdeš na chuť budeš ho používat i častěji. Je to docela šikovná věc.

 
Nahoru Odpovědět 15. června 15:45
Avatar
petr.dar
Člen
Avatar
petr.dar:

Jasně, jsou dobrý možná jako konverzní funkce, ale jinak všude možně používám ukazatele a odkazy abych se jim vyhnul.

 
Nahoru Odpovědět 15. června 15:59
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na petr.dar
Taskkill:

A když používáš třeba clone(), tak je to v podstatě to samé jako kopírák ne?

 
Nahoru Odpovědět 15. června 16:52
Avatar
petr.dar
Člen
Avatar
Odpovídá na Taskkill
petr.dar:

Podle názvu to asi bude pravda, ale já jsem žádný clone() nikdy nepoužil, ani na cplusplus stránkách jsem to nikde nenašel :-D

 
Nahoru Odpovědět 15. června 16:59
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na petr.dar
Taskkill:

To je metoda objektu, která vytvoří jeho klon, tedy dokonalou kopii, používá se to tehdy, pokud návrh neumožňuje jiné řešení, než poslat někam klon objektu a původní objekt nechat tam kde byl, nebo ho zničit. Třeba kvůli bezpečnosti a kontrole výskytu těchto objektů v programu.

 
Nahoru Odpovědět 15. června 17:31
Avatar
petr.dar
Člen
Avatar
Odpovídá na Taskkill
petr.dar:

Ano, přesně jako kopírovací konstruktor, akorád mě bylo divný, že píšeš clone() jako funkci

 
Nahoru Odpovědět 15. června 17:46
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na petr.dar
Taskkill:

To není kopírující konstruktor, to je metoda clone(), konstruktor zavoláš jen tak v prostoru, stejně tak ten kopírující, kdežto clone() se volá, musí volat, na již existující instanci. Třeba takto

Human clovek = new Human("Franta", 23); // beznej konstruktor
Human druhejClovek = new Human(); // defaultni

Human tretiClovek = new Human(clovek); // kopirak

nejakaFunkce(tretiClovek.clone()); // clone() udela kopii tretiClovek a vrati referenci na novej objekt, tedy nejakaFunkce dostava klona od tretiClovek a ne jeho referenci
 
Nahoru Odpovědět 15. června 17:53
Avatar
petr.dar
Člen
Avatar
Odpovídá na Taskkill
petr.dar:

jo takhle, to vyzkoušim, akorád ještě řešim co když budu mít v objektu nějaký ukazatel, ten se nemůže zkopírovat, ale vytvořit novej, to by tim asi nešlo že jo.

 
Nahoru Odpovědět 15. června 18:08
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na petr.dar
Martin Dráb:

Pokud nepotřebuješ ten objekt kopírovat nějak speciálně (tzn. v jeho atributech nejsou čisté ukazatele např.), myslím, že nemusíš kopírovací konstruktor vůbec psát, protože toto obstará jeho výchozí verze (ta prostě kopírovacím konstruktorem okopíruje všechny atributy).

Co se týče memmove, pro kopírování se vyplatí použít jen v případě, že se zdrojový a cílový buffer překrývají (funkce se chová tak, jako by tam byl ještě dočasný buffer, přes nejž kopírování probíhá, takže překrývání není problém). Pokud víš, že se zdrojový a cílový buffer nepřekrývají, tak použij memcpy.

Nahoru Odpovědět 15. června 18:13
2 + 2 = 5 for extremely large values of 2
Avatar
Martin Dráb
Redaktor
Avatar
Martin Dráb:

To není kopírující konstruktor, to je metoda clone(), konstruktor zavoláš jen tak v prostoru, stejně tak ten kopírující, kdežto clone() se volá, musí volat, na již existující instanci. Třeba takto

Tak, on to je spíš takový syntaktický detail. Metodu clone voláš na instanci, což znamená, že ona vlastně dostane tu instanci jako parametr (jistě, není to přímo vidět, ale implementace je taková). Kopírující konstruktor si danou instanci bere jako explicitní parametr.

Takže není problém napsat:

nejakaFunkce(new Human(tretiClovek));

Spíš je to o tom, že v některých jazycích (C++) kopírovací konstruktory máš, ale ne metodu clone a v nějterkých jazycích zase metodu clone máš (Java), ale nemáš kopírovací konstruktor.

Nahoru Odpovědět 15. června 18:18
2 + 2 = 5 for extremely large values of 2
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na petr.dar
Martin Dráb:

ještě řešim co když budu mít v objektu nějaký ukazatel, ten se nemůže zkopírovat, ale vytvořit novej, to by tim asi nešlo že jo.

To záleží, zda-li si tu věc, na kterou ten ukazatel vede, přeješ zkopírovat či nikoliv. Pokud ano, tak v rámci kopírovacího konstruktoru či metody clone musíš ono kopírování pořešit (pokud to je ukazatel na třídu, stačí na ní zavolat kopírovací konstruktor resp. metodu clone a může být hotovo).

Nahoru Odpovědět 15. června 18:20
2 + 2 = 5 for extremely large values of 2
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na petr.dar
Taskkill:

Jde o tohle, pokud si přeješ aby se při kopírování objektu nějaká jeho property (kdyby třeba v sobě mel objekt pole) zkopírovala natvrdo, nikoliv jenom reference, tak si musíš napsat kopírující konstruktor sám, v něma alokovat místo pro nové pole a přetahat obsah.

Jakože mám clovek1 = {skills: ["C++", "JS", "JAVA"]};

když teď pošlu clovek1 do kopirujícího konstruktoru, a výsledek uložím jako clovek2, tedy

clovek2 = new Human(clovek1);

tak mam pro pole skills mělkou kopii, jakmile začnu upravovat pro clovek2 jeho skilly, upravuju je i pro clovek1. Tohle nutně ne vždy chceme, takže pokud nechceme, napíšeme si vlastní kopírující konstruktor.

To jestli se provede mělká nebo hluboká kopie by default je docela zásádní a když si člověk není jistej, měl by to pokrýt nějakým experimentem.

 
Nahoru Odpovědět 15. června 18:25
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na Martin Dráb
Taskkill:

Samozřejmě, můžeš je nahrazovat, dokud nepotřebuješ implementovat program tak, že není možné poslat stávající objekt, není možné vytvořit kopírákem novej a je nutné použít clone(), který si sám napíšeš pro svou classu, ono takhle to zní strašně umělě, ale já to zmiňuju kvůli jednomu zajímavýmu případu co jsem jednou viděl na přednášce, kde se tímhle hlídala unikátnost objektů (implementace zoologické zahrady) prostě nešlo vytvořit novýho lva, nešlo starýho poslat jen tak do novýho pavilonu, protože by programátor mohl nechat původní instanci v původním pavilonu a Lev se nám už buněčně dělí jak bakterie, tak tam byla metoda pro přesun zvířete z pavilonu, v jednom ho to zničilo v druhém vyplivnulo, takovej teleport. Netvrdím, že to byl nejlepší příklad, no prostě klasickej příklad na pochopění na vejšce.

 
Nahoru Odpovědět 15. června 18:30
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na Taskkill
Martin Dráb:

K tomuto účelu by asi sloužil move assignment/con­strutor (C++11), který má navíc tu výhodu, že neprovádí vlatně kopírování. Ale už hodně záleží, jak ten příklad byl udělán, je možné, že by se musel celý přepsat.

Samozřejmě se dá i kokpírák napsat tak, aby nevytvořil novou instanci, pokud se to nesmí.

Podle mě pak už hodně záleží na tom, zda takové řešení bude pěkné/čitelné, nebo zda bude vidět, jak moc se na to člověk snažil napasovat dané konstrukty.

Nahoru Odpovědět  +1 15. června 18:38
2 + 2 = 5 for extremely large values of 2
Avatar
petr.dar
Člen
Avatar
Odpovídá na Martin Dráb
petr.dar:

Děkuji všem za vyčerpávající info, jen po jistotu bych chtěl upřesnit ( jestli jsme to dobře pochopil), že teda memmove se používá v poli, kvůli tomu překrývání, a memcpy se používá když mám ukazatele zvlášť oddělené, takže vlastně v tom mým prvním dotazu nešlo použít memmove, ale právě memcpy :-)

 
Nahoru Odpovědět 15. června 21:19
Avatar
Martin Dráb
Redaktor
Avatar
Odpovídá na petr.dar
Martin Dráb:

Děkuji všem za vyčerpávající info, jen po jistotu bych chtěl upřesnit ( jestli jsme to dobře pochopil), že teda memmove se používá v poli, kvůli tomu překrývání, a memcpy se používá když mám ukazatele zvlášť oddělené, takže vlastně v tom mým prvním dotazu nešlo použít memmove, ale právě memcpy :-)

V C/C++ je pole implementováno jako ukazatel. Tzn. tyto dva zápisy jsou "v podstatě" ekvivalentní:

int a[25];
int *a;

Rozdíl je v tom, že v prvním případě překladač ví, že se jedná o pole o délce 25 a že tento prostor alokuje a nasměruje na něj proměnnou a, kdežto v druhém případě se jedná o ukazatel, který musíš naplnit něčím užiečným, než jej legálně použiješ. V obou případech ale můžeš napsat:

a[10] = 256;

Takže to, zda použiješ memcpy či memmove není závislé na tom, zda se jedná či nejedná o pole. Prostě pokud víš, že se zdroj a cíl nepřekrývá, použij memcpy, jinak **memmove. Ani pole se nemusejí překrývat. Obecně se dá říci, že se zdroj a cíl překrývají jen velmi zřídka.

Nahoru Odpovědět 15. června 21:38
2 + 2 = 5 for extremely large values of 2
Avatar
Taskkill
Redaktor
Avatar
Odpovídá na Martin Dráb
Taskkill:

Já teda vůbec nechci mít poslední slovo nebo tak něco, ale když pro zjednodušení říkáš nováčkovi že pole je v podstatě ukazatel, bylo by dobrý jim říct, že to není docela pravda, aby se na to dívali takhle, dokud to nechápu, ale pak, že to chce hlubší pochopení. Vím že jsi to napsal do uvozovek, ale on to z toho každý nepochopí, jinak naprosto respektuji, že to pro zjednodušení takhle uvádíš.

 
Nahoru Odpovědět  +1 15. června 22:00
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 22 zpráv z 22.