Lukemassani kirjassa suositellaan käyttämään vapaata muistialuetta, koska "Vapaalla muistialueella olevat kohteet säilyvät funktion päättymisen jälkeen". Kuitenkin, aiemmin mainitaan että, koska osoitin itse on paikallinen muuttuja, se menetetään funktion päättyessä ja syntyy muistivuoto eli new-operaattorilla varattu muisti jää käyttökelvottomaksi. Eli mitä hyötyä on vapaasta muistista, kun se kuitenkin jää käyttökelvottomaksi funktion loputtua, jos osoitin on paikallinen??
E: kyseessä siis C++
Tämän tiedon perusteella on vaikea sanoa, mitä kirjassasi tarkoitettiin.
Esim. seuraava tapaus on ihan toimiva (olettaen, että siinä ei ole typoja):
char* varaaja(int koko) { char* taulukko = malloc(koko); if (taulukko != NULL) { for (int i = 0; i < koko; i++) { taulukko[i] = 0; } } return taulukko; }
tässä tapauksessa varatun muistin sijaintitietoa ei menetetä, koska se palautetaan paluuarvona, joten muistivuotoa ei synny.
EDIT: C++ ei poikkea paljoa tässä suhteessa C:stä, korvaat vain sanan "malloc(koko)" tekstillä "new char[koko]" ja teet virhetarkastelut (muistivarauksen onnistumisesta) C++:n tapaan.
Nyt kannattaa itsenäisesti miettiä ihan ajatuksella.
Hyvän ohjelmointitavan mukaisesti varattu muisti pitää aina vapauttaa, kun sitä ei enää tarvita. Jos tuota varattua muistialuetta tarvitaan muualla, kuin kyseisessä funktiossa, voi aina käyttää globaalia osoitinta tai sitten yksinkertaisesti palauttaa funktiosta osoittimen.
L2-K2,
siis vapaa muisti tarkoittaa sitä, kun luodaan esim. osoitin
int *Pointer = new int;
tässä siis luodaan osoitin, joka osoittaa johonkin int-muodolle sopivaan osoitteeseen. En tajua tuossa koodissasi malloc()-funktiota, mikset käytä new-operaattoria?
ja jalski,
juu tässä sitä on pohdittu jo hetki ennen kuin tänne postasin. Ei vaan mee jakeluun, että mikä etu siinä vapaassa muistissa on verrattuna paikallisiin (tai globaaleihin) muuttujiin. Yhtä hyvinhän nekin voi palauttaa funktiosta?
Tämäntyyppisten "monimutkaisempien" rakenteiden edut eivät tule esiin kuin erikoistapauksissa. Yleensä jos jossain toteutuksessa ei näe mitään etua, ei sitä kannata käyttää.
Tässä tapauksessa tämä rakenne on välttämätön esim. linkitetyn listan toteuttamiseen. Esim (huom. koodi ei todennäköisesti käänny):
struct solmu { int arvo struct solmu * seuraava; }; void alusta_lista(struct solmu **alku, int arvo) { *alku = new struct solmu; (*alku)->arvo = arvo; (*alku)->seuraava = NULL; } /* * Lisätään arvo linkitettyyn listaan. (Lista täyttyy olla alustettu tässä * vaiheessa, jolloin siellä on vähintään yksi alkio.) */ void lisaa_arvo_listaan(struct solmu **alku, int arvo) { // Etsitään listan häntä. struct solmu * kulkija = * alku; while (kulkija->seuraava != NULL) { kulkija = kulkija->seuraava; } // Lisätään listan häntään uusi alkio. kulkija->seuraava = new struct solmu; kulkija->seuraava->arvo = arvo; kulkija->seuraava->seuraava = NULL; }
Jos käyttämällesi kääntäjälle voi antaa parametrin, millä se tekee assembly listauksen objekti-tiedoston sijaan, niin kokeile sitä ja tutki listauksesta miten lokaalien muuttujien muisti varataan funktioissa.
Alla esimerkki omasta keskeneräisestä assemblyllä kirjoitetusta OS/2 WPS-luokasta.
samdisk_init proc near push ebp mov ebp, esp sub esp, 0x0000001C ; varataan tila lokaaleille muuttujille hab = [ebp-0x00000004] hwnd_client = [ebp-0x00000008] hwnd_frame = [ebp-0x0000000C] flCreate = [ebp-0x00000010] somSelf = [ebp-0x00000014] client_data = [ebp-0x00000018] somThis = [ebp-0x0000001C] ... ; tässä tehtäisiin jotain fiksua ; lopussa näet yleensä jotain tälläistä mov esp, ebp pop ebp ret samdisk_init endp
EDIT: sorry, copy/pastasin väärän kohdan ensin ja rivit päin peppua.
noniin, kiitos asiallisista vastauksista :)
Aihe on jo aika vanha, joten et voi enää vastata siihen.