Přidat otázku mezi oblíbenéZasílat nové odpovědi e-mailem C++ Alokacia a dealokacia pamati

Caute ucim sa C++ sorry za zaciatocnicke otazky ale rad by som si par veci ujasnil.

V C++ si programator moze zvolit kde alokuje pamat, ci na stacku alebo na halde. takze prva otazka:

1. kedy zvolit stack a kedy heap?
2. Dalsia vec chcem si ujasnit aky je rozdiel medzi tymito 3omi instanciaciami objektov?

auto objekt1 = Trieda();
objekt1.Metoda();
 
auto objekt2 = new Trieda();
objekt2->Metoda();
 
auto objekt3 = &Trieda();
objekt3->Metoda();

Prvy vytvara objekt na stacku. Druhy na halde a treti tiez na halde? Takze druhy a treti zapis je eqvivalentny?

3. kedy uvolnovat pamat? Ako zabranit tomu aby nastali memory leaky. Odkedy sa ucim C++ tak som zatial na ziadny problem nenarazil a to vobec nevolam delete. Takze aj v C++ sa uvolnuje pamat automaticky? Kedysi som programoval v Delphi a tam sa kazdy objekt musel uvolnit rucne procedurou Free() inak spadla cela aplikacia, take nieco sa mi v C++ este nestalo, preco?

4. kedy pouzit shared_pointery

5. aku knihu o C++ mi viete doporucit? Idealne aby bola podrobna, aktualna (C++11).

Předmět Autor Datum
Na to "auto objekt1 = Trieda();" a tie dalsie 2 si prisiel jak? Ptz je to hovadina. Vseobecne zo st…
MM.. 02.02.2014 11:26
MM..
Normalny clovek pouziva normalne zapisy. Napr. class Rectangle { int width, height; public: void set…
MM.. 02.02.2014 11:30
MM..
A este klucove slovo auto pouzivat nemusis, ptz ani nevies co znamena. (//edit: nie ze nemusis ale t…
MM.. 02.02.2014 11:40
MM..
este dodam k tomu bodu 4., ak myslis triedu shared_ptr, tak to je trieda ktoru uz niekto naprogramov…
MM.. 02.02.2014 12:05
MM..
A este dodaok k bodu 3. free volas samozrejme len na veci alokovane pomocou new, t.j. na veci ktore…
MM.. 02.02.2014 12:09
MM..
první a druhý způsob se spíš "týká"~používá v javascriptu, kde je rozdíl mezi voláním funkce a vytvá…
mnua.al 02.02.2014 11:50
mnua.al
Skusim ti nacrtnut jak sa v C++ robi s triedami normalne, zaklady (ziadne pokricle hardcore). Trieda…
MM.. 02.02.2014 13:07
MM..
MM: Vdaka za odpovede ale mam v tom este vacsi gulas. Pisal si ze ten treti zapis je zly, ale sprav…
mikser 02.02.2014 13:19
mikser
Pouzivanie auto je totalne nebezpecna zhovadilost ptz tym odstavujes najdolezitejsiu vyhodu C, a to…
MM.. 02.02.2014 13:23
MM..
Práve naopak, auto je skvelá a navyše štandardizovaná vec, zvlášť v prípade iterátorov. C nás v tomt…
los 02.02.2014 13:25
los
Ale ved o automaticke odvodzovanie typov sa stara prekladac, takze ta typova kontrola tam stale je.…
mikser 02.02.2014 13:39
mikser
ale neni to mozno presne ten typ ktory si chcel. 5 moze byt char, unsigned char, int unsigned int, i…
MM.. 02.02.2014 13:52
MM..
alebo ina vec x=10; x+=3000000000; if(x>15) printf("spravne"); else printf("nespravne"); a skus si…
MM.. 02.02.2014 13:54
MM..
1. Stack volíš vtedy, keď nepotrebuješ, aby tá trieda žila dlhšie. Heap zasa v tých ostatných prípad…
los 02.02.2014 13:20
los
Vdaka za odpovede.
mikser 02.02.2014 13:25
mikser
gcc zvlada auto? Druha vec je napr. zapis auto i=100; i+=0xFFFFFFFF; kolko bude i? ;) Vies na co n…
MM.. 02.02.2014 13:27
MM..
Myslel som samozrejme g++, keďže sa bavíme o C++ (g++ -std=c++11 ...). Premenná i bude typu int. Ak…
los 02.02.2014 13:37
los
BTW. ak pominiem to hardcore s tym iteratorom, ty by si napisal namiesto Motorka x; auto x = Motorka…
MM.. 02.02.2014 13:36
MM..
V tomto prípade by som to napísal normálne. Ale tie iterátory sú pre auto ako stvorené.
los 02.02.2014 13:43
los
Je to mozne, ja som konzerva, taketo veci ma zasadne ani nenapadnnu (a napr. na poslednu vec ktoru s…
MM.. 02.02.2014 14:07
MM..
To sa nedá tak, že deklaruješ iba auto y. Musí sa použiť initializer, aby bolo z čoho ten typ možné…
los 02.02.2014 14:55
los
auto y = NULL; Fcia1(y); :-) Ja viem bude asi error (y bude void* alebo int?), ale ako spravna konz…
MM.. 02.02.2014 16:15
MM..
y bude int. void* by to bol vtedy, ak by si spravil "auto y = nullptr". Keď robíš klasické pretypov…
los 02.02.2014 16:51
los
si predstav strukturu struct tralala { struct tramtaram x; int dalsi; } struct tramtaram { int dalsi…
MM.. 02.02.2014 17:16
MM..
BTW. nepoznal som to (ja som zakysol u MS 2009), takze vdaka za objasnenie pouzitia napr. u tych ite… poslední
MM.. 02.02.2014 17:30
MM..

Na to
"auto objekt1 = Trieda();" a tie dalsie 2 si prisiel jak? Ptz je to hovadina.

Vseobecne zo stacku sa alokuje vsetko to co je lokalne (zmizne po ukonceni funkcie. T.j. napr. vsetky lokalne premenne, je uplne jedno ci su typu obycajne int, alebo typu trieda). Viz google co to je stack.
A vsetko co je staticke resp. globalne (prezije ukoncenie funkcie) sa musi alokovat z normalnej pamate.

Programatorovi to je uplne uprdele odkial sa to alokuje, pre neho je dolezite aby nevytvaral nekonecne mnozstva statickych veci, ptz tym pouzije celu RAM. C++ sa cloveka snazi dostat k tomu aby nepotreboval takmer nic staticke, s vynimkou jednej instancie hlavnych veci t.j. aplikacie apod, v ktorej su potrebne staticke data, pripadne pointre na dynamicky alokovane data (normalne cez malloc apod)

A este klucove slovo auto pouzivat nemusis, ptz ani nevies co znamena. (//edit: nie ze nemusis ale tak jak ho pouzivas ho NEPOUZIVAJ NIKDY a to SAKRA NIKDY ptz vytvaras totalne nekompatibilny zdrojak. Viz //edit2: kua este aj blby link som dal :D Spravny
http://msdn.microsoft.com/en-us/library/6k3ybftz.a spx Idem asi robit daco ine :D

K dotazom:

Prvy vytvara objekt na stacku. Druhy na halde a treti tiez na halde? Takze druhy a treti zapis je eqvivalentny?

Nie. Treti nic nevytvara. Treti je IMHO error :)

3. kedy uvolnovat pamat? Ako zabranit tomu aby nastali memory leaky. Odkedy sa ucim C++ tak som zatial na ziadny problem nenarazil a to vobec nevolam delete. Takze aj v C++ sa uvolnuje pamat automaticky? Kedysi som programoval v Delphi a tam sa kazdy objekt musel uvolnit rucne procedurou Free() inak spadla cela aplikacia, take nieco sa mi v C++ este nestalo, preco?

ked neuvolnis pamat tak nic nespadne, len ostane alokovana (zabrana) pamat. Ked ti nieco spadlo, tak si to chybne naprogramoval. Free musis pouzit na veci ktore uz nepotrebujes a alokoval si ich pomocou new. Dobry zvyk je okamzite invalidovat pointer ktory sa testuje pri volaniach ci je v nom validna adresa

4. kedy pouzit shared_pointery

to si zas nabral odkial taky duchaplny vyraz? Pointerov mozes mat kolko chces, trebars aj milion, a mozu ukazovat vsetky trebars aj na to same miesto, tomu pocitacu to je uplne fuk kam ukazuju. Kedy ktory pointer kam nastavit zavisi snad od datoveho modelu ktory si si pre dany problem vymyslel.

5. aku knihu o C++ mi viete doporucit? Idealne aby bola podrobna, aktualna (C++11).

neviem uz 25rokov necitam knihy. Skus zacat nejakym tutorialom, dufam ze vies anglicky, je ich na google asi trilion.

este dodam k tomu bodu 4., ak myslis triedu shared_ptr, tak to je trieda ktoru uz niekto naprogramoval, pouzivat ju mozes ale nemusis. Ako zaciatocnik to nepotrebujes. Vpodstate k pointru pridali dalsie veci ako napr. pocitadlo ze kto kazdy dany pointer potrebuje (ten zavola patricnu metodu a tym sa pocitadlo zvysi) a ked uz ho nikto nepotrebuje (ak kazdy zavolal inu metodu ze ho nepotrebuje) tak ta trieda alokovany objekt uvolni a nastavi hodnotu pointra na invalid.
Takych uz pripravenych tried je milion, mozes ich pouzivat az si nastudujes vsetky ich metody a pochopis jak presne funguje, ale nemusis to pouzivat vobec, mozes si spravovat globalne pointre na globalne data aj sam.

A este dodaok k bodu 3.
free volas samozrejme len na veci alokovane pomocou new, t.j. na veci ktore si alokoval sam, z haldy. nevolas to na veci zo stacku samozrejme, ptz stack sa neda alokovat/uvolnovat jak ta napadne, uvolnenie stacku je pevne zviazane s navratom z funkcie.

Skusim ti nacrtnut jak sa v C++ robi s triedami normalne, zaklady (ziadne pokricle hardcore). Trieda je len sablona (informacia pre compiler) ktora popisuje ako budu vypadat objekty danej triedy. Trieda samotna (ten popis class blablabla) pri vykonavani programu nezabera ziadnu pamat, je to len navod ako vytvarat objekty. Napr. zadefinujem si triedu

class Motorka {
 protected:
  int kubatura;
 public:
  Motorka() {kubatura = 0;}  // defaultny konstruktor
  Motorka(int k) {kubatura = k;} // konstruktor s parametrom
...tu budu nejake funkcie dalsie apod...
};

- teraz este neni alokovana ziadna pamat.

A mozem napr. vytvorit objekt v ramci jednej fcie, objekt pri navrate z funkcie bude zniceny, stejne jak ostatne lokalne premenne, napr. jak to int i

void funkcia()
{
 int i;
 Motorka moje_faro(3000); // vytvori sa objekt moje_faro a zavola vola sa konstruktor s parametrom 3000
 Motorka ine_faro; // vytvori sa objekt ine_faro a zavola vola sa defaultny konstruktor

... nieco robim s objektami moje_faro a ine_faro...
 moje_faro.VypisJakeMamFajneFaro();
...
} // tu sa objekty znicia stejne tak jak premenna i.

Alebo mozem napr. definovat objekt ako sucast ineho objektu v inej triede, napr.

class Zoznam100Motoriek {
  Motorka zoznam[100];
...tu budu nejake funkcie dalsie apod...
};

- ked niekto vytvori objekt tejto triedy, tak sa v pamati vpodstate vytvori 100objektov triedy Motorka.

Alebo mozem definovat pointer na objekt (tym sa nevytvori objekt samotny!) a potom si do neho priradit nejaku adresu, ak si vytvorim objekt alebo alokujem dynamicke pole pre vela objektov apod.

Motorka* vytvaracia_funkcia()
{
 Motorka* p=NULL;

...
 p = new Motorka; // zavola sa default konstruktor lebo je to bez parametra
...

 return(p); //mozem vratit pointer ptz objekt nezanikne na konci fcie
}; // tu sa znici premenna p, objekt ostane v pamati.

void main(void)
{
 Motorka* m;
 if(m = vytvaracia_funkcia() != NULL) {
  m->VypisJakeMamFajneFaro();
  delete(m); // ked uz objekt viac nepotrebujem tak delete objektu.
 }
}

Apod. Na presun medzi funkciami nemusis pouzivat smerniky, objekty sa daju presuvat ako navratova hodnota aj hodnotou, vtedy aj objekt alokovany zo stacku na konci funkcie akokeby nezanikol (on zanikne ale skopiruje sa do ineho objektu vo volajucej funkcii):

Motorka vytvaracia_funkcia()
{
 Motorka x(1000);
...
 return(x); //mozem vratit objekt hodnotou (skopiruje sa, BTW.: moze byt pomale)
}; // tu sa znici objekt x, ale bol predtym skopirovany do volajucej fcie.

void main(void)
{
 Motorka m;
 m = vytvaracia_funkcia();
 m.VypisJakeMamFajneFaro();
} // tu sa znici objekt m.

Alebo presuvas parametre odkazom, to je vpodstate stejne jak to s pointrom, len sa nepise pointer ale Motorka& a pouziva sa akokeby objekt, t.j. ne m->Neco ale m.Neco

P.S. zapis Trieda() ktore si dal v dotaze je z principu nezmysel, je to defakto kontruktor triedy ktory akokeby volas, a ziaden objekt neexistuje. Ak to compiler pochopi tak OK, ale je to neskutocne matuci a nelogicky zapis.

MM:

Vdaka za odpovede ale mam v tom este vacsi gulas. Pisal si ze ten treti zapis je zly, ale spravil som si testovaciu applikaciu a ono mi to funguje:

#include <iostream>
#include <cstring>

using namespace std;

class Trieda
{
public:
	void Metoda(wstring input)
	{
		wcout << input.c_str() << endl;
	}
};


void main()
{
	auto objekt1 = Trieda(); // ekvivalent Trieda objekt;
	objekt1.Metoda(L"Objekt alokovaný na stacku");
	auto objekt2 = new Trieda();
	objekt2->Metoda(L"Objekt alokovaný na heape");
	auto objekt3 = &Trieda();
	objekt3->Metoda(L"Objekt alokovaný na ???");
	system("pause");
}

Akurat som sa mylil v tom ze ten treti zapis je eqvivalentny tomu druhemu. Nie je podla vsetkeho sa asi vytvara na stacku a do premennnej sa uklada referencia na tento objekt.

Viem co znamena auto je to keyword z C++ 11 pouziva sa pri type inference to iste ako keyword var v C#, v tomto pripade na sprehladnenie zdrojaku. Viem ze takyto zdojak nebude kompatibilny so starsimi verziami C++ ale ja uz kompatibilitu so starsimi verziami ani neriesim chcem sa naucit novy standard so vsetkymi featurami ako lambdy atd.

a o shared pointeroch sa pise napriklad tu: http://babel.blog.root.cz/2012/04/11/sprava-pameti -v-c/ vraj sa pri ich pouziti nemusim starat o uvolnovanie pamate, pretoze sa pouzije pocitadlo referencii.

Pouzivanie auto je totalne nebezpecna zhovadilost ptz tym odstavujes najdolezitejsiu vyhodu C, a to je typova kontrola. Navyse doraz sa kladie vzdy na prenositelnost kodu, ptz visal MS nejaka hovadina 2010 zajtra moze prestat existovat :D A pozajtra pride sef a povie ti ze potrebuje ten program pre linux.

Treti zapis je poniter na funkciu, co je uplny nezmysel ak neexistuje ovjekt.

ale neni to mozno presne ten typ ktory si chcel. 5 moze byt char, unsigned char, int unsigned int, int64, apod.
Rozdiel medzi signed a unsigned je totalne zasadny, napr. urob si program
x=10;
x-=20;
if(x<5) printf("spravne");
else printf("nespravne");

a skus si to s x signed a unsigned. A auto bude teda co? Typy a typova kontrola je extremne dolezita vec. Ak by si napr. pri if mixoval signed a unsigned dostanes warning apod.

alebo ina vec
x=10;
x+=3000000000;
if(x>15) printf("spravne");
else printf("nespravne");

a skus si to s auto na 32bitovom prekladaci.

P.S> Narazam na to ze pri alokacii premennej je ZASADNA vec jaku bude mat v pamati reprezentaciu, a to ma posudit programator ze jaku reprezentaciu tam chce mat (kvoli limitnym hodnotam a pouziti danej premennej apod). Neda sa to nechat na prekladac (a ak ano tak to je nebezpecne ptz programator nepouzil mozog a limity su nahodne a programator ani nevie jake su tie limity)
P.S> napr. pri praci s offsetmi suborov je unsigned kriticky, a kontroluje sa to aj u parametrov volani fcii, apod. S auto tam budes mat neco. A mozno dostanes aj warning. Truba bude ignorovat aj warning, hlavna vec ze pouzil auto.

1. Stack volíš vtedy, keď nepotrebuješ, aby tá trieda žila dlhšie. Heap zasa v tých ostatných prípadoch.

2a. Inštancia objekt1 je alokovaná na stacku. Po opustení bloku je automaticky uvoľnená.
2b. Inštancia objekt2 je alokovaná v heape. Po opustení bloku zostáva v pamäti.
2c. Inštancia triedy je alokovaná na stacku, pričom v objekt3 je uložený smerník na túto inštanciu. Po opustení bloku je inštancia uvoľnená.

3. Pamäť uvoľňuješ vtedy, keď už s daným objektom nepotrebuješ pracovať. V C++ sa pamäť uvoľňuje automaticky len v prípade, že je objekt na stacku. Ak alokuješ v heape, tak musíš uvoľňovať podobne ako v Delphi.

4. shared_ptr použiješ vtedy, keď chceš, aby sa inštancia automaticky uvoľnila vtedy, keď ju už nikto nepoužíva. Vďaka počítaniu referencií sa pamäť uvoľní automaticky. Je to v podstate to isté, ako interfejsy v Delphi.

Kľúčovému slovu auto by som sa vôbec nevyhýbal. Namiesto zápisov typu "std::map<std::string, std::map<std::string, std::string> >::iterator it" vo for cykloch použiješ "auto it". V C++ by som práveže uprednostňoval všetky štandardné vlastnosti jazyka, ako sú shared_ptr, unique_ptr, move constructory a podobne. Keď to zvláda VS2013 a gcc, tak nie je čo riešiť.

BTW. ak pominiem to hardcore s tym iteratorom, ty by si napisal namiesto
Motorka x;
auto x = Motorka();
?
2x viac pismen. Navyse je to matuce a nejasne (neviem okamzite ci to Motorka() je trieda alebo nejak funkcia o 3 strany dalej alebo jakeho svateho vynalez. Mysli aj na toho kto to bude citat o rok po tebe... :)

Je to mozne, ja som konzerva, taketo veci ma zasadne ani nenapadnnu (a napr. na poslednu vec ktoru som robil pred rokom na VC++ bola aby to slo aj na Win98 :). S novymi MS kravinami compilermi ti ten vytvor nepojde ani na XP, nie to este na 98 :)
Neviem ci tam je kriticke jaky typ pouzijes u iteratoru, ja by som sa vyhol aj samotnemu iteratoru a robil to nejak konzervativne :D Ok to je fuk. Este ma napada dalsia vec, a to je overloaded funkcie, povedzme ze mam
Fcia1(int* a);
Fcia1(char* a);

int x;
Fcia1(&x); // pohoda

auto y;
Fcia1(&y); // ?????

:)

auto y = NULL;
Fcia1(y);

:-) Ja viem bude asi error (y bude void* alebo int?), ale ako spravna konzerav povazujem zavadzanie takychto noviniek za silnu zhovadilost. Problem je v tom ze ak pisem funkciu tak pri klasickom sposobe mam kontrolu nad tym co robim, a v pripade ze cudzia fcia vracia nieco ine dostatnem error.
Napr.
int x; // chcem robit s int
x=CudziaFunkcia(); // ak nevracia int ale napr. int* tak dostanem error apod
auto x=CudziaFunkcia(); // nedostanem error, neviem s cim vlastne pracujem, aj ked sice mozem dostat error dalej, ale ak napr. pri low level veciach pretypujem hned x napr na int* ptz chcem pristupit na adrtesu ktoru mi vratil niekto ako cislo, nedostatem error ziaden. Apod. Je to odstranenie urcitej kontroly, ak napr. ak je gulas vo funkciach a niekto updatuje cudzie funkcie tak ze vracaju nieco ine apod. Ano da sa to povazovat aj ako vyhoda ze hura ked updatujem cudziu funkciu ze bude vracat nejaku inu nemusim prepisovat aj volajuce funkcie, ale nemusi to byt vzdy bezpecne to pouzivat. Nech si na to dava radsej pozor.

si predstav strukturu
struct tralala
{
struct tramtaram x;
int dalsi;
}
struct tramtaram
{
int dalsi;
int predosly;
}

A ty sa pomylis a myslis si ze fcia vracia struc tralala, ale ona vracia struct tramtaram. Ked pouzijes
auto x = DajStrukturu();
tak si tu chybu vobec nevsimnes, ptz ak urobis if(x->dalsi == NULL) neco tak nedostanes ziaden error.
Ak by som ale jasne napisal co si myslim ze tam chcem dostat
struct tralala *x;
x = DajStrukturu();
tak dostamen error od compilera s textom "ty trubka ta funkcia vracia pointer na tramtaram, daj si kafe a kukaj poriadne". Kontroly su na to aby odhalovali chyby programatora, a nie na to aby sa v dalsej verzii nahradili nejakym skvelym auto pre debilov co prechadzaju z visualbasicu :) Ja len vysvetlujem preco mi to auto je proti srsti, netvrdim ze to je uplne nepouzitelne ale hlavne novacikom by som ruky olamal keby mi to pouzivali aj na obycajne int (len sranda :-))

Zpět do poradny Odpovědět na původní otázku Nahoru