Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





Pasar como argumento del constructor una estructura.

Iniciado por Pepius, 03 de Septiembre de 2009, 08:51:33 PM

« anterior - próximo »

Pepius

Hola,

Estoy programando un videojuego y quiero que los enemigos carguen sus datos (puntos de vida, trayectoria, etc...) de un archivo de texto. Con tal fin, he creado una estructura que alberga todos los datos llamada EnemyData. La idea era hacer una lista con todas las estructuras EnemyData, y que el constructor de la clase del enemigo (Enemy) recibiera como argumento un puntero a una estructura del tipo EnemyData. Para mi sorpresa, parece ser que esto no se puede hacer o (mucho más probable) lo estoy haciendo mal, porque el código compila y se ejecuta sin problemas, pero haciendo debug me da un error SIGSEGV, que según he googleado parece ser violación de segmento.

He ido aislando el problema hasta llegar a la conclusión de que el problema está ahi. Copio aquí la estructura (que no tiene ningun misterio) y el perfil del constructor.

typedef struct{
    int ID;
    SpriteSet *sset;
    int health;
    int score;
    float startx;
    float starty;
    float velocity;
    int total_waypoints;
    WayPointData waypoints[N];
    int total_shots;
    ShotData shots[N];
    int powerup_id;
    int bullet_id;
}EnemyData;


Enemy(EnemyData *edata):GameEntity(edata->sset,edata->startx,edata->starty),data(edata)

¿Puede que el problema esté al pasar el constructor de la clase Base? ¿Estoy haciendo una burrada?

Si necesitais más parte del código me lo decís.

Muchas gracias :)

Pogacha

Eso que pusiste no tiene ningun error.
pone mas codigo si queres

Mars Attacks

#2
Lo más lógico es que le sigas la pista a todos esos punteros que usas; quizá en algún lado los estás eliminando (o no se los has pasado bien a la estructura, por no haberlos creado donde crees que los estabas creando).

Edito: intenta acostumbrarte siempre a crear un constructor para la propia estructura, que inicialice los valores por defecto. Funcionan exactamente igual que el constructor de una clase.

Edito 2: Me alegra ver que sigues dando guerra por ahí :)

Pepius

#3
Gracias por vuestras respuestas :D

Mars, gracias por lo de crear el constructor, no sabia que en C++, las estructuras eran una clase. Hábito adquirido :)

Bueno, creo que he arrinconado ya el problema. A ver si consigo explicarme:

En el main.cpp tengo la siguiente funcion:

int load_enemy_data(char *path){

char image_path[30];
int col,rx,ry,total;
        std::ifstream infile(path);
        ...
        infile >> image_path;
infile >> col >> rx >> ry >> total;
        ...
        EnemyDataList[n_ED].sset = new SpriteSet(image_path, col, rx, ry, total);
infile.close();
       ...
}

(He omitido partes irrelevantes)

Como podeis ver, la función carga desde un archivo de texto los diferentes campos de la estructura. Y lo hace sin problemas. El problema viene cuando intento acceder, desde el int main, a la instancia de la clase SpriteSet que acabo de crear.

Por ejemplo, si yo intento lo siguiente:

    std::cout << EnemyDataList[0].sset->columns << std::endl;


O sea, printear una variable (desde el int main) de la instancia (la variable es pública) que he creado en la anterior función, es cuando me da el error.

Si en cambio, el "new" lo hago desde el int main, no me da problema.

No se si me explico... un saludo y gracias.

Pepius

Vale, creo que lo encontrado. Que alguien me lo explique, por favor.

Si la función int load_enemy_data, la cambio por void load_enemy_data y, por tanto, le quito el return, no me da el error.

A que se debe esto, alguien me lo podria explicar?

Gracias, un saludo.

Pogacha

Ese tipo de error son siempre por escribir o leer en una direccion de memoria no permitida, son errores de proteccion. Con el fragmento de codigo que has puesto no es posible determinar el error.
Saludos

Pepius

Si, eso lo habia supuesto. Lo que no me cuadra es que me deje acceder a dichas zonas protegidas en tiempo de ejecución y que el error me lo de al salir. Lo que tampoco me cuadra es que esto ocurra solo cuando reservo la memoria en una función que retorna un valor, pero que no ocurra cuando la reservo en una función void.  La verdad es que no hay mucho mas codigo que enseñar, si eso mas tarde copypasteo la función entera y el main.

Gracias por las respuestas, un saludo.

Pepius

No lo entiendo, me aparece el mismo error por otro lado. Debo de tener algún problema de concepto o algo, porque no puede ser que me de tantas veces contra la misma pared. Copio codigo:

#include <SDL.h>
#include "Entities.h"

#include <fstream>
#include <list>
using std::list;

list <EnemyData*> EnemyDataList;
list <Enemy> EnemyList;

EnemyData* ID2ED(int ID){
    list<EnemyData*>::iterator it;
    it = EnemyDataList.begin();

    while((*it)->ID!=ID && it!=EnemyDataList.end()){
        //std::cout << it->ID << std::endl;
        ++it;
    }

    if((*it)->ID==ID){
        return *it;
    }
    else
        return NULL;
}
/*
int ID2ED(int ID){
    int i;
    for(i=0;i<n_ED;i++){
        if(EnemyDataList[i].ID==ID){
            return i;
        }
    }
    if(i==n_ED){
        return NULL;
    }
}
*/
void load_enemy_data(char *path){
    EnemyData *edata=new EnemyData;
char image_path[30];
int col,rx,ry,total;
int i;
std::ifstream infile(path);

if (!infile) {
        std::cout << "Problema al obrir l'arxiu " << path <<"."<<std::endl;
        //return 0;
    }

infile >> edata->ID;
infile >> image_path;
infile >> col >> rx >> ry >> total;
infile >> edata->health;
infile >> edata->score;
infile >> edata->powerup_id;
infile >> edata->startx;
infile >> edata->starty;
infile >> edata->velocity;
infile >> edata->total_waypoints;

for(i=0;i< edata->total_waypoints;i++){
infile >> edata->waypoints[i].x >> edata->waypoints[i].y;
}
infile >> edata->total_shots;
for(i=0;i< edata->total_shots;i++){
infile >> edata->shots[i].time >> edata->shots[i].dx >> edata->shots[i].dy >> edata->shots[i].lifetime;
}
infile >> edata->bullet_id;
edata->sset = new SpriteSet(image_path, col, rx, ry, total);
EnemyDataList.push_back(edata);

infile.close();
std::cout << "Enemic amb ID: \"" << edata->ID << "\" carregat."<<std::endl;
//return 1;
}

int main(){
    EnemyData *edata;
    load_enemy_data("DataTest");
    edata = ID2ED(3);
    std::cout << "edata: " << edata->health << std::endl; //Si quito esta linea, no me da error.
    std::cout << EnemyList.empty()<< std::endl;

    EnemyDataList.clear();
    EnemyList.clear();
    return 0;
}


load_enemy_data carga de un archivo de texto los elementos de la estructura, y despues el puntero a esa estructura lo agrega a la EnemyDataList, que es una lista de *EnemyData (punteros).

ID2ED, recibe un entero, recorre la lista de *EnemyData buscando una estructura con el campo ID igual al entero que ha recibido, y devuelve un puntero a esa misma estructura. Cuando intento acceder a esa estructura mediante el puntero que ha devuelto ID2ED es cuando me da el error.

Ains... un saludo y gracias, otra vez.

Pogacha

1)

Antes de esta linea:
edata->sset = new SpriteSet(image_path, col, rx, ry, total);

controla que todos los datos que cargaste esten bien, sean los que se suponen deben cargar.

2 )

    EnemyData *edata = new edata;
  edata->xxx = efefe;
    list<EnemyData*>->push( edata )


es mal diseño

    list<EnemyData> enemy_data
    enemy_data.push_back( EnemyData() );
    EnemyData& edata = enemy_data.back();
    edata.xxx = efefe;


es bastante mejor ... incluso se puede mejorar mas aun.

al final:

    EnemyDataList.clear(); 
    EnemyList.clear();

Estas haciendo un hermoso memory leak! nunca estas haciendo delete de los elementos que creaste con new, con el otro diseño no es necesario.


Pepius

#9
Gracias por la respuesta Pogacha, se agradece de verdad tu tiempo  ^_^'

Si, me he dado cuenta despues, es que aun no tenia claro como funcionaban las listas y al estar tan obsesionado con el maldito error, he perdido todas las formas a la hora de programar.  El punto 1) está comprobado. Muchas gracias por el punto 2), paso a aplicarlo inmediatamente.

He solucionado el problema dando un pequeño rodeo, pero aun no me queda claro porque no puedo hacer segun que cosas con punteros. Sigo programando, iré poniendo cosas por aqui.

Muchas gracias otra vez.

Pepius

Guau, muchas gracias por el punto 2, definitivamente. Va como la seda. Gracias de verdad :)






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.