[C++] - Problema Allocazione Dinamica Oggetto

di il
15 risposte

[C++] - Problema Allocazione Dinamica Oggetto

Buongiorno a tutti,

Qualche giorno fa mi sono imbattuto in un problema che non riesco a risolvere.
Scrivendo un piccolo giochino, implementando la morte del personaggio, nella funzione in questione, quando vado a deallocare e allocare nuovamente la memoria per ripristinare alle condizioni iniziali dell'oggetto personaggio fatte tramite costruttore, non ricevo nessun errore.

Quando invece esco dalla funzione per proseguire con il ciclo di gioco, i valori degli attributi dell'oggetti vengono cambiati, provocando l'esecuzione di altre funzioni o di cicli infiniti.

Ho pensato fosse un problema di scope, ma essendo dei puntatori a oggetto, questo non dovrebbe influire, per di più il problema si è presentato nel momento in cui sono passato da visual studio 2015 a visual studio 2017, in quanto con vs15 il programma funzionava correttamente senza alcun problema

Grazie per il vostro aiuto, Riccardo

15 Risposte

  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    Senza vedere il codice nelle parti di cui parli é impossibile fare un commento.
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    Ecco qua, questa è la funzione in questione
    void GameEngine::collisionBulletPlayer(std::vector <ProiettileNemico> &proiettile_nemico, Player *player, Camera *camera)
    {
    	//per ogni proiettile, cioè per l'intera grandezza del vettore
    	for (int i = 0; i < proiettile_nemico.size(); i++)
    	{
    		//prendo la posizione del proiettile e del nemico
    		player->box = player->getGlobalBounds();
    		proiettile_nemico[i].box = proiettile_nemico[i].getGlobalBounds();
    
    		//se il rettangolo del nemico interseca quello del proiettile
    		if (player->box.intersects(proiettile_nemico[i].box))
    		{
    			player->vita -= proiettile_nemico[i].danno;
    
    			if (player->vita <= 0)
    			{
    				delete player;
    				player = new Player;
    
    				delete camera;
    				camera = new Camera;
    			}
    			proiettile_nemico.erase(proiettile_nemico.begin() + i);
    		}
    	}
    }
    Fino a questo punto tutto normale, i valori sono corretti. Quando esco da questa funzione i valori degli attributi dell'oggetto player sono cambiati
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    Quali attributi sono cambiati?
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    Non vorrei dire una sciocchezza, ma se riallochi gli oggetti li dovresti passare così
    Player **player, Camera **camera
    altrimenti il chiamante continuerà ad utilizzare i puntatori alla memoria deallocata.
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    candaluar ha scritto:


    Non vorrei dire una sciocchezza, ma se riallochi gli oggetti li dovresti passare così
    Player **player, Camera **camera
    altrimenti il chiamante continuerà ad utilizzare i puntatori alla memoria deallocata.
    Ho provato a passarli in questo modo, ma mi da errore di compilazione a causa della conversione da *player a **player, vale lo stesso per la camera.

    oregon ha scritto:


    Quali attributi sono cambiati?
    Tutti quanti, i loro valori sono come le variabili non inizializzate.
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    Ho provato a passarli in questo modo, ma mi da errore di compilazione a causa della conversione da *player a **player, vale lo stesso per la camera.
    Naturalmente devi cambiare da, per esempio, player->vita a (*player)->vita ...
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    Naturalmente devi cambiare da, per esempio, player->vita a (*player)->vita ...
    Chiaro, errore mio.
    Dopo aver provato a sostituire player-> con la dicitura che mi hai suggerito, il risultato non è cambiato.

    Ho solamente cambiato la funzione in cui era presente la riallocazione.

    Non ho provato a cambiare tutti i riferimenti nel resto del programma a ogni chiamata a player, quindi chiedo se è una cosa che potrebbe servire.
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    In C++ una scrittura molto più comoda è:
    
    Player*& player, Camera*& camera
    
    così si può mantenere la scrittura player->dato riflettendo le modifiche all'esterno.
    Domanda: ma succede anche se non entri in ? :
    
             if (player->vita <= 0)
             {
                delete player;
                player = new Player;
    
                delete camera;
                camera = new Camera;
             }
    
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    Si, ho provato a eseguirlo fuori da ogni if e anche fuori dal for, il risultato non cambia.

    La prima dichiarazione di questi oggetti è effettuata nel main, prima di entrare nel ciclo principale, è una cosa che può influire?

    Nel passaggio da vs15 (programma funzionante) a vs17 ho dovuto aggiungere staticamente una libreria esterna,(prima era aggiunta dinamicamente) però la parte del problema non tocca la libreria.

    Da quello che ho studiato, utilizzando i puntatori con NEW e DELETE, dovrei agire direttamente sulla memoria, quindi non mi spiego ne il comportamento dell'oggetto che viene "azzerato" all'uscita della funzione, e sinceramente, questa è solo per la mia ignoranza, i consigli che mi avete dato in precedenza. Per essere più chiaro, capisco il significato di ciò che mi avete consigliato, ma non la loro reale utilità.

    Grazie
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    Per quel che vedo, solo entrando in quel if invalidi i parametri player e camera, in quanto prima li distruggi e poi li ricostruisci chissa come.
    Se il problema persiste anche con una semplice chiamata vuota, allora il problema è fuori da quella funzione e senza vedere il codice del main e delle classi e librerie coinvolte non è possibile capire che sta succedendo.
  • Re: [C++] - Problema Allocazione Dinamica Oggetto


    Ultima istruzione della funzione, ovviamente dopo aver chiamato la distruzione e la ricostruzione


    Istruzione successiva alla precedente

    Main:
    #pragma once
    #include "Header.h"
    
    int main()
    {
    	//dichiarazione oggetti
    	Finestra finestra;
    	Comandi comandi;
    	TileMap tileMap;
    	Camera *camera = new Camera;
    	Player *player = new Player;
    	std::vector <Proiettile> proiettile;
    	std::vector <ProiettileNemico> proiettile_nemico;
    	GameEngine gameEngine;
    	std::vector <Enemy> nemico;
    	Effect effetto;
    	Menu *menu = new Menu;
    	Opzioni *opzioni = new Opzioni;
    
    	//ciclo principale
    	while (finestra.isOpen())
    	{	
    		comandi.setCommand(finestra, camera, player, proiettile, menu, opzioni);
    
    		gameEngine.run(player, proiettile, camera, nemico, tileMap, effetto, menu, proiettile_nemico, opzioni);
    
    		finestra.disegna(tileMap, camera, player, proiettile, nemico, effetto, menu, proiettile_nemico, opzioni);
    
    	}
    
    	return 0;
    }
    La libreria esterna che ho utilizzato è SFML
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    ovviamente dopo aver chiamato la distruzione e la ricostruzione
    Quindi in quell'if ci entri. E ti aspetti che poi in uscita sia player sia camera contengano qualcosa di valido?
    Una volta distrutto un oggetto, ciò che contiene è definitivamente perso. Se poi lo ricrei hai qualcosa che non è nemmeno parente di quel che era prima. E in uscita hai qualcosa che non c'entra niente con quello in entrata.
    Tra l'altro non hai specificato se Player e Camera abbiano dei costruttori di default, per cui assumo che non ne abbiano nessuno.
    In più non è affatto necessario fare una delete e una successiva new, ma è sufficiente implementare un metodo reset() ai due oggetti, in modo che rimangano in uno stato noto, ma neutro rispetto al codice.
    P.S.
    Non postare immagini in quanto non si vede niente e ingrandendole si sfocano.
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    Quindi in quell'if ci entri
    Sia che io entri nell'if, sia che non entri, quindi provando distruggere e ricostruire gli oggetti al di fuori di ogni if/for, il risultato non cambia.
    Una volta distrutto un oggetto, ciò che contiene è definitivamente perso. Se poi lo ricrei hai qualcosa che non è nemmeno parente di quel che era prima. E in uscita hai qualcosa che non c'entra niente con quello in entrata.
    Chiaro, io distruggo gli oggetti per poi ottenerne di completamente nuovi.

    Costruttore
    
    Player::Player()
    {
    	x = 0;
    	y = 0;
    	this->texture.loadFromFile("Assets/Player/Anim_player_2.png");
    	this->setTextureRect(sf::IntRect(x, y, 64, 64));
    	this->setTexture(texture);
    	size = texture.getSize();
    	this->setOrigin(size.x/2/8, size.y /2 /4);
    	this->setPosition(sf::Vector2f(size.x/2/8, 300));
    	box = this->getGlobalBounds();
    	dead = false;
    	jump = false;
    	flip = false;
    	vita = 700;
    	movimento = 3;
    	spinta = -18;
    }
    
    implementare un metodo reset()
    Si era un idea a cui avevo pensato, ma allo stesso tempo avevo anche pensato che potevo utilizzare il costruttore.
  • Re: [C++] - Problema Allocazione Dinamica Oggetto

    Sia che io entri nell'if, sia che non entri, quindi provando distruggere e ricostruire gli oggetti al di fuori di ogni if/for, il risultato non cambia.
    Ovvio che il risultato non cambi se distruggi e ricrei oggetti in quella funzione. Che siano all'interno di if o for è un dettaglio insignificante. Il punto è che stai usando puntatori locali alla funzioni, pertanto le ricostruzioni restano all'interno della funzione. Se vuoi che il tutto si trasmetta al di fuori dei passare dei doppi puntatori (più scomodo che sconsigliato) o dei reference ai puntatori (consigliato).
    In pratica devi modificare il prototipo così:
    
    void GameEngine::collisionBulletPlayer(std::vector <ProiettileNemico> &proiettile_nemico, Player*& player, Camera*&  camera)
    
    e devi farlo per ogni funzione in cui prevedi distruzioni e riallocazioni di puntatori che debbano essere visibili all'esterno.
    Nota però che questo non serve quando devi solo modificare delle variabili membro.

    A ogni modo, distruggere e ricreare oggetti in quel modo è sconsigliato, in quanto le allocazioni possono sollevare eccezioni (e causare dei memory leaks), sono pesanti dal punto di vista prestazionale e sono comunque aggirabili con opportuni metodi di classe.
    Se proprio ti piace quel modo, puoi usare il placement delete e il placement new, senza passare per reference i puntatori in oggetto, senza allocazioni extra di memoria e ricostruendo player e camera nella stessa locazione di memoria già allocata.
    
            if (player->vita <= 0)
             {
                player->~Player(); // placement delete
                new (player) Player(); // placement new
    
                camera->~Camera(); // placement delete
                new (camera) Camera(); // placement new
             }
    
Devi accedere o registrarti per scrivere nel forum
15 risposte