Tervehdys kaikille jälleen...
Pitää kyllä myöntää, että alkaa hieman jo hävettää, koska C/C++ alueella taitaa kohta olla ensimmäisellä sivulla pelkkiä minun perustamini aiheita. Suuri anteeksipyyntö tämän johdosta.
...noh, jottei tämä viesti mene aivan itkemiseksi, esitämpä tämän minun ongelmani. Eli tuli tuota softaani tekiessä pieni probleema SDL_Surface:en kanssa.
Eli ongelma on se, että hakiessani vectori "images":ta kuvan Draw funktiolle ja koitan piirtää ruutuun kuvaa, niin ohjelma kaatuu. Itse epäilen jonkin moisen muistipaikan nollautumista, mutta itse en näe koodissa mitää vikaa, mikä voisi kaataa ohjelman.
...tämä on todella vaikee selittää, joten teen niin, että jos tarvitaan lisä tietoa, niin kysykää, niin minäpä kerron. :)
Kiitos jälleen etukäteen todella paljon!!!
Tähän malliin
//IMAGE structi struct IMAGE{ string name; SDL_Surface *surface; }; class DRAW{ public: //Constructori DRAW(); //Ikkunan luonti bool CreateImage(string filename, string imgName); //Vapautus funktio (käy läpi vektorin jokaisen pinna, ja vapauttaa sen) void FreeSurfaces(); //Hakee "nimen" perusteella kuvan vektorista SDL_Surface* getSurface(string imgName); //Piirto funktio void Draw(SDL_Surface *screen, string imgName, int x, int y); private: //Luo vektorin joka periytetään IMAGE sturctista vector<IMAGE> images; };
...tässä vielä draw.cpp funktioiden määrittelyt
#include "draw.h" DRAW::DRAW(){} bool DRAW::CreateImage(string filename, string imgName){ //Luoda väliaikais kuvan SDL_Surface *tempSurface = SDL_LoadBMP(filename.c_str()); //Luo IMAGE tyypisen väliaikais "olion"? ja tallentaa siihen nimen ja tempSurfacesta kuvan. IMAGE tempImg; tempImg.name = imgName; tempImg.surface = tempSurface; //Siirretään väliaikais IMAGE vektoriin images.push_back(tempImg); //Vapautetaan väliaikais pinta SDL_FreeSurface(tempSurface); } void DRAW::FreeSurfaces(){ //Silmukka käy läpi vektorin ja vapauttaa niissä olevat pinna (käytetää ohjelman sulkeutuessa) for(int i = 0; i < images.size(); i++ ){ SDL_FreeSurface(images.at(i).surface); } } SDL_Surface* DRAW::getSurface(string imgName){ //Luo tyhjän pinnan varmuuden vuoksi, jos haettua kuvaa ei löydy SDL_Surface *empty; //Käy silmukassa läpi vektorin ja vertaa vastaako haetun kuvan nimi kuvan nimeä, jos vasaa palautetaan kuva for(int i = 0; i < images.size(); i++ ){ if( imgName == images.at(i).name ){ SDL_FreeSurface(empty); return images.at(i).surface; } } //Jos kuvaa ei löytynyt, palautetaan tyhjä pinta return empty; } void DRAW::Draw(SDL_Surface *screen, string imgName, int x, int y){ SDL_Surface *drawSurface = getSurface(imgName); SDL_Rect rect; rect.x = x; rect.y = y; SDL_SetColorKey(drawSurface, SDL_SRCCOLORKEY, SDL_MapRGB(drawSurface->format,255,0,255)); SDL_BlitSurface(drawSurface, NULL, screen, &rect); SDL_FreeSurface(drawSurface); }
Voisiko johtua siitä että vapautat kuvan/surfacen heti lataamisen jälkeen?
Mitä tarkoitat? Tarkoitatko siis kohtaa CreateImage-funktiossa, jossa vapautan tempSurface? Jos kyse on siitä, kokeilin jo ennen ennenkuin kirjoitin tänne, kommentoida tuon rivin poijes, mutta se ei auttanut.
tempImg.surface ja tempSurface ovat osoittimia, jotka osoittavat samaan paikkaan sillä hetkellä millä vapautat tempSurfacen.
En täysin hallitse c++:ssaa mutta eikö tuo empty-surfacekin ole null? Eli yrität vapauttaa nullia.
Eli siis siinä tapahtuu juuri sitä mitä epäilinkin, eli tieto joka siirretään vektoriin, osoittaa loppujen lopuksi tyhjään paikkaan. Eli käsittääkseni CreateImage-funktion jälkeen tieto, joka tallenetaan vektoriin on turhaa, koska itse tieto johon pointteri osoittaa on tuhoutunut? Tätäkö meinasit?
Tuota empty pinnan luonti onkin periaatteessa turha, olen kyllä kokeillu suorittaa ohjelmaa ilman että sitä luodaan, mutta ei auttanut. En kuitenkaan usko, että empty pinnan luonti olisi syy, vaan uskon ehkä ennemmin ylhäällä sepittämääni tekstiin.
SDL_FreeSurface(tempSurface);
Tämän jälkeen pinta on vapautettu. Koska koodissasi käsittelet vain osoittimia SDL-pintoihin, tempSurface ja tempImg.surface osoittavat samaan pintaan, ja kun vapautat pinnan, kumpikaan osoittimista ei enää toimi. Ainoa oikea ratkaisu on tavalla tai toisella pitää kirjaa siitä, tarvitaanko pintaa vielä, ja kutsua SDL_FreeSurfacea vasta, kun kyseistä kuvaa ei enää käytetä (eli kun se poistetaan vektorista).
Erityisen hankala ongelmasta tulee siksi, että delete
ei nollaa osoitinta, eli koodin kannalta näyttää, että surface
olisi vieläkin kelvollinen osoitin. Valitettavasti muisti on kuitenkin jo vapautettu, eli osoitin osoittelee haudan taakse.
kayttaja-3842 kirjoitti:
Eli siis siinä tapahtuu juuri sitä mitä epäilinkin, eli tieto joka siirretään vektoriin, osoittaa loppujen lopuksi tyhjään paikkaan. Eli käsittääkseni CreateImage-funktion jälkeen tieto, joka tallenetaan vektoriin on turhaa, koska itse tieto johon pointteri osoittaa on tuhoutunut? Tätäkö meinasit?
Juuri niin.
kayttaja-3842 kirjoitti:
Tuota empty pinnan luonti onkin periaatteessa turha, olen kyllä kokeillu suorittaa ohjelmaa ilman että sitä luodaan, mutta ei auttanut. En kuitenkaan usko, että empty pinnan luonti olisi syy, vaan uskon ehkä ennemmin ylhäällä sepittämääni tekstiin.
Saako SDL_FreeSurface-funktiota kutsua nullilla tai jo vapautetulla surfacella (randomilla muistipaikalla)?
Nytten se toimii!!! Kiitos paljon. :)
Metabolix kirjoitti:
Erityisen hankala ongelmasta tulee siksi, että
delete
ei nollaa osoitinta, eli koodin kannalta näyttää, ettäsurface
olisi vieläkin kelvollinen osoitin. Valitettavasti muisti on kuitenkin jo vapautettu, eli osoitin osoittelee haudan taakse.
Yksi tapa on opetella käytäntö, jossa osoitin asetetaan osoittamaan nullia, kun sen osoittama muisti on vapautettu. Sekä tutkia osoittaako osoittin nulliin ennen osoittimen käyttöä.
kayttaja-2499 kirjoitti:
Yksi tapa on opetella käytäntö...
Tietenkin tapoja on. Mitä ohjelmoinnista tulisikaan, jos bugit olisivat väistämättömiä? :) Tuossakin tilanteessa pitäisi silti joka kerta tarkistaa osoittimen arvo ja ehkä jättää kuva piirtämättä, joten ongelma ei ole ratkennut, vaan vasta sen suurin haitta (ohjelman kaatuminen) on estetty.
Tarkoitin oikeastaan, että ongelma on joskus hankala paikallistaa tai ohjelman toimivuus tarkistaa, kun kaikki vapautettuun muistiin osoittavat osoittimet eivät maagisesti muutu nulleiksi eikä mistään saa varsinaisesti selville, onko tietyn muistiosoitteen muisti sattumoisin vapautettu.
Ihan vain selvennyksenä. :)
Kysyjän ongelma näyttää olevan siinä, että ajatukset osoitinmuuttujan arvosta ja siitä, mitä tuon arvon osoittamassa muistipaikassa on, menevät sekaisin. Surface ja siihen osoittavat osoittimet eivät ole sama asia, mikä ehkä alkoikin jo selvitä.
Osoitinmuuttujien nollaamisesta on keskusteltu ennenkin. Nollaaminen on tapauksesta riippuen joko tarpeellista, aivan turhaa tai suorastaan vahingollista. Ei siis kannata tuudittautua mihinkään käytäntöön vaan toimia tilanteiden mukaan.
Aihe on jo aika vanha, joten et voi enää vastata siihen.