Siirry sisältöön

C/Omistajuuden siirto

Wikikirjastosta
< C

Yleisesti ottaen hyvään ohjelmointitapaan kuuluu, että muistin varaaminen (malloc) ja vapauttaminen (free) hoidetaan saman tahon toimesta. Molemmat voidaan esimerkiksi tehdä samassa funktiossa tai jos kyseessä on abstrakti tietotyyppi tai muu struct-rakenne, hoitaa destruktori muistin vapauttamisen, varausten tapahtuessa konstruktorissa ja mahdollisesti muissakin funktioissa. Näin varaamiset ja vapauttamiset ovat aina löydettävissä siisteinä pareina samasta paikasta ja on helppoa varmistaa, ettei ohjelmassa ole muistivuotoja ja ettei samaa muistia yritetä vapauttaa useaan kertaan.

Ajoittain on kuitenkin tarvetta siirtää jokin resurssi paikasta toiseen ilman kopiointia. Tyypillisiä tapauksia ovat sellaiset, joissa lisätään objekteja tietorakenteesen tai jos objektia ei syystä tai toisesta ole mahdollista kopioida, mutta se kuitenkin halutaan siirtää.

Esimerkki lisäämisestä käyttäen kuvitteellista MovieList-kontaineria ja Movie-ADT:tä. Tässä movieListAdd ei siirrä omistajuutta, vaan tekee elokuvasta kopion (movieCopy-funktiolla).

MovieList* ml = movieListConstruct();
Movie* movie = movieConstruct("Star Wreck: In The Pirkinning", 2005);
movieListAdd(ml, movie);
movieDestruct(movie);
movie = movieConstruct("Big Buck Bunny", 2008);
movieListAdd(ml, movie);
movieDestruct(movie);
movie = NULL;  // To avoid accidentally using an invalid pointer
/* ... */
movieListDestruct(ml);

Elokuvien lisääminen listalle tällä tapaa on kohtuuttoman työlästä, sillä jokainen elokuva on luotava, tallennettava muuttujaan ja listalle lisäämisen jälkeen tuhottava. Jos movieListAdd-funktion semantiikkaa muutetaan siten, että lisätyn elokuvan omistajuus siirtyy listalle, siis sen sijaan, että parametrina annettu elokuva kopioitaisiin listalle, onnistuu lisääminen huomattavasti helpommin:

MovieList* ml = movieListConstruct();
movieListAdd(ml, movieConstruct("Star Wreck: In The Pirkinning", 2005));
movieListAdd(ml, movieConstruct("Big Buck Bunny", 2008));
/* ... */
movieListDestruct(ml);

Tässä ei synny muistivuotoa, vaikka äkkiseltään siltä saattaisikin näyttää, koska tässä versiossa movieListAdd ottaa sille annetun elokuvan omistajuuden (takes ownership) ja on siten vastuussa muistin vapauttamisesta. Käytännössä samalla vältetään myös elokuvan kopiointi, koska movieListAdd voi edelleen tallentaa itselleen annetun pointterin listalle, jolloin movieListDestruct aikanaan huolehtii elokuvan tuhoamisesta.

Resurssin (objektin) omistajuudella siis tarkoitetaan käytännössä sitä kenen vastuulla on vapauttaa resurssi (vapauttaa muisti) tai välittää omistajuus edelleen eteenpäin. Alussa resurssin omistaa aina se, joka sen on varannutkin.