Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: SDL - Segfault

Sivun loppuun

Lumi-ukkeli [11.07.2006 17:35:32]

#

#ifndef _Pinta__h__
#define _Pinta__h__
#include <SDL/SDL.h>
#include <string>
#include <iostream>
#include <fstream>

class Pinta
{
    public:
        Pinta::Pinta(std::string Name)
        {
            std::ofstream printer;
            printer.open("Pinta.txt", std::ios::app);
            SurfacePointer = NULL;
            m_released = false;
            m_surfCount++;
            m_name = Name;
            printer << m_name << " allocated. ";
            printer << m_surfCount << " objects left.\n";
            printer.close();
        }

        Pinta::~Pinta()
        {
            Free_Surface();
        }

        void Pinta::SetName(std::string NewName)
        {
            m_name = NewName;
        }

        void Pinta::Free_Surface()
        {
            std::ofstream printer;
            printer.open("Pinta.txt", std::ios::app);
            printer << "just trying to free " << m_name << "\n";
            if(!m_released)
            {
                SDL_FreeSurface(SurfacePointer);
                m_released = true;
                SurfacePointer = NULL;
                m_surfCount--;
                printer << m_name << " released. ";
                printer << m_surfCount << " objects left.\n";
            }
            printer.close();
        }
        SDL_Surface* SurfacePointer;
    private:
        static int m_surfCount;
        bool m_released;
        std::string m_name;

};
#endif
#include "SDL.h"
#include <iostream>
#include "Pinta.h"
void draw();
Pinta foo("test surface");
int Pinta::m_surfCount = 0;
/* The screen surface */
SDL_Surface *screen = NULL;

int main (int argc, char *argv[]) {

    int done;

    /* Initialize SDL */
    if (SDL_Init (SDL_INIT_VIDEO) < 0)
        std::cerr << SDL_GetError() << "\n";

    atexit (SDL_Quit);

    screen = SDL_SetVideoMode (1024, 768, 32, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_FULLSCREEN);
    if (screen == NULL)
        std::cerr << SDL_GetError() << "\n";

    Pinta temp("temp surface");
    temp.SurfacePointer = SDL_LoadBMP("tileset32.bmp");
    foo.SurfacePointer = SDL_DisplayFormat(temp.SurfacePointer);
    temp.Free_Surface();


    done = 0;
    while (!done)
    {
        SDL_Event event;

        /* Check for events */
        while (SDL_PollEvent (&event))
        {
            switch (event.type)
            {
            case SDL_KEYDOWN:
                done = 1;
                break;
            case SDL_QUIT:
                done = 1;
                break;
            default:
                break;
            }
        }

        /* Draw to screen */
        draw ();
    }

    return 0;
}



/* This function draws to the screen; replace this with your own code! */
void draw () {
    /* Make sure everything is displayed on screen */
    SDL_Rect d = {0, 0, 0, 0};
    SDL_BlitSurface(foo.SurfacePointer, NULL, screen, &d);

    SDL_Flip (screen);
    /* Don't run too fast */
    SDL_Delay (1);
}

Ja muistivuotoa access violation segfault pukkaa, ja en tiedä miksi.

Metabolix [11.07.2006 17:47:42]

#

Segfault ei ole muistivuoto! Muistivuoto on sellainen, että varataan muistia ja jätetään se vapauttamatta. Segfault on yleensä sellainen, että tökitään muistia, joka ei ohjelmalle kuulu.

Minulla tuo toimi kyllä. Onhan kuva varmasti olemassa? Sen lisäksi suosittelisin, että luovut tuosta m_released-muuttujasta ja tarkistat sen sijaan, onko SurfacePointer NULL.

Kaiken kukkuraksi tuollaisenaan tuo luokka ei niin hirvittävän hyvin ehkäise muistivuotoja, kun pinnan pystyy asettamaan ulkoa käsin. Sinuna tekisin jotenkin näin:

class TPinta {
  private:
    SDL_Surface *pinta;
  public:
    SDL_Surface *hae_pinta() {return pinta;}
    void aseta_pinta(SDL_Surface *uusi)
    {
      if (pinta) {
        SDL_FreeSurface(pinta);
      }
      pinta = uusi;
    }
};

Näin sillä olisi jo toivoa. Vielä parempi olisi piilottaa kaikki SDL:n kuvanluonti- ja -latausfunktiot käyttäjältä ja hoitaa nekin jäsenfunktioilla.

Lumi-ukkeli [11.07.2006 17:53:45]

#

Kyllä mullaki toimii siihen asti että suljen ohjelman. Sitten Windows herää henkiin ja olis lähettämässä virheraportteja microsoftin pelleille.

Tiedän, että tuo on huono luokka, mutta idea ei olekaan että se on käytännöllinen. Yritän vain metsästää tuota segfaulttia.

Omituisen tuosta tekee se, että tuo tapahtuu vain jos globaaleja pinosta varattuja Pinta-luokan olioita sörkitään SDL_DisplaySurface():lla, jolloin ohjelma kaatuu kun se sammutetaan. Kokeilkaapa vaikka poistaa displaysurface() ja ladata kuva suoraan foo-pintaan.

Metabolix [11.07.2006 18:21:34]

#

Kyllä tuo koodi toimii aivan ongelmitta, ei mitään virheilmoitusta tai muuta. Jopa gdb sanoo, että "program exited normally". Lisäile nyt varmuuden vuoksi vähän lisää tulostusta ja selvitä, missä kohti tuo virhe tulee.

Jos koodia ei aio käyttää, on suhteellisen turhaa metsästää sieltä segfaulttia. Tyypillisesti se johtuu yksinkertaisesti siitä, että jossakin on Bugi isolla B:llä, ja jos koodia ei mihinkään tarvitse, sen voi aivan hyvin heittää mäkeen. :)

Lumi-ukkeli [17.07.2006 13:46:15]

#

Mun kääntämä ohjelma kaatuu kun ohjelma kutsuu tuhoajaa globaalille foo-objektille -> tuhoaja kutsuu Free_Surface() ja siellä tarkalleen ottaen rivillä SDL_FreeSurface(SurfacePointer);
Tarkastin, että SurfacePointer != NULL;
Microsoft Visual C++ 6.0 kertoo virheilmoitukseksi tarkalleen "Unhandled exception in testprj.exe (SDL.DLL): 0xC0000005: Access Violation"

Tosiaan - segfaulttia siinä ei siis ollutkaan.

Yritän saada tämän toimimaan, koska käytän paljon parempaa Pinta-luokkaa oikeissa projekteissani, mutta niissäkin on täsmälleen tämä sama ongelma. Yksinkertaistin luokkaa niin paljon kuin osasin, jotta teidän olisi helppo tutkia tuota koodia.

Olisikohan mahdollista, että SDL_Quit() kutsutaan ennen nuita globaalien SDL_FreeSurface()? Minun tietääkseni sen pitäisi olla sallittua? Onkohan mun SDL.DLL:ssä jotain vikaa?

Ilmeisesti oli, kun hain uusimman version dll:stä ja vika hävisi...

Lumi-ukkeli [25.07.2006 12:42:31]

#

En kyl tiä kuuluuko tää tänne ollenkaan mut jatkoa tää on tuolle: Tuo ongelma tapahtuu siis vain kuin ajurina toimii directx. Tuo uudempi dll vaihtoi oletukseksi windib, jolla tuo ongelma katosi (jostain kumman syystä mun näyttö sirittää??), mutta jos eksplisiittisesti vaihdan uudella dll:llä ajurina käytettäväksi juuri directx niin tuo ongelma palaa takaisin.

Drifter [26.07.2006 11:02:13]

#

btw, Access Violation == Segmentation Fault

Metabolix [26.07.2006 14:29:39]

#

Kirjastot eivät ole haavoittumattomia. Kuten tuosta virheilmoituksesta itse asiassa näkeekin, virhe tulee SDL.DLL:n sisällä. Olettaisin, että DirectX:n sammuttaminen (SDL_Quit -> SDL_VideoQuit -> DX5_VideoQuit) tekee pintojen vapauttamisesta mahdotonta. Suosittelen siis, että lisäät atexit-funktiolla loppuun suoritettavaksi funktion, joka huolehtii globaalien pintojen vapauttamisesta ja kutsuu vasta sen jälkeen SDL_Quit-funktiota. Muutenkin, jos ei ole aivan erityistä syytä käyttää globaalia pintaa, en näe sellaisen käytössä juurikaan järkeä.


Sivun alkuun

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta