Pagina 2 di 2 primaprima 1 2
Visualizzazione dei risultati da 11 a 20 su 20

Hybrid View

  1. #1
    Utente di HTML.it L'avatar di gaten
    Registrato dal
    Jul 2007
    Messaggi
    1,269
    Un'altra cosa che mi rende perplesso è:

    codice:
    test->getComponent<AI_followTarget>()
    restituisce NULL, ma poi test() su quale istanza lo richiama? ?? ??

    test() in AI_followTarget è un metodo di istanza.

    ho provato a fare questo O.O:

    codice:
    AI_followTarget *a = NULL;
     a->test();
    mi richiama perfettamente il metodo test() di AI_followTarget
    Ultima modifica di gaten; 13-10-2014 a 00:28
    Con i sogni possiamo conoscere il futuro...

  2. #2
    Quote Originariamente inviata da gaten Visualizza il messaggio
    Un'altra cosa che mi rende perplesso è:

    codice:
    test->getComponent<AI_followTarget>()
    restituisce NULL, ma poi test() su quale istanza lo richiama? ?? ??

    test() in AI_followTarget è un metodo di istanza.

    ho provato a fare questo O.O:

    codice:
    AI_followTarget *a = NULL;
     a->test();
    mi richiama perfettamente il metodo test() di AI_followTarget
    Come già detto, è undefined behavior; stai violando le regole del linguaggio, dato che stai richiamando un metodo d'istanza su una istanza non valida, per cui tutto può succedere. Il C++ non effettua alcun controllo sostanzialmente per motivi di prestazioni.

    Per chiarire come mai nel tuo caso tutto sembra funzionare, bisogna guardare "sotto il cofano" e vedere come sono implementate effettivamente le classi.

    Nella maggior parte delle implementazioni, una classe, a livello di codice generato, è equivalente ad una struct contenente i suoi campi e a delle "normali" funzioni libere che ricevono il "this" (ovvero, l'istanza su cui operare) come parametro nascosto. Per questo motivo, codice di questo tipo:
    codice:
    class A
    {
        int a;
        double b;
    
        void doSomething(int value)
        {
            a=value;
            b=value*2.5;
        };
    };
    
    ...
    A test;
    test.doSomething(15);
    Di fatto è come se fosse
    codice:
    struct A
    {
        int a;
        double b;
    };
    
    void A_doSomething(A *this, int value)
    {
        this->a=value;
        this->b=value*2.5;
    }
    
    ...
    A test;
    A_doSomething(&test, 15);
    La faccenda in realtà si complica un po' quando ci vanno di mezzo funzioni virtuali, i distruttori, ereditarietà multipla e compagnia, ma il concetto di fondo è sempre questo - quando chiami un metodo su un'istanza, di fatto stai chiamando una "normale" funzione passandole l'istanza su cui deve operare come parametro "nascosto".

    Venendo al tuo caso, è chiaro a questo punto come mai non incontri errori eclatanti: la tua classe ha un metodo test che non fa alcun uso del puntatore this (di fatto potrebbe essere tranquillamente un metodo static), per cui, anche se richiamato su un'istanza non valida (o addirittura NULL), non si accorge nemmeno del problema, dato che riguarda un dato di cui non fa alcun uso.

    Ribadisco comunque che questo non è assolutamente un comportamento supportato, e va considerato una circostanza fortunata (o meglio, sfortunata, dato che nasconde un bug) il fatto che in questo caso non ottieni un crash. Oltre al fatto che basta cambiare qualcosa (rendi il metodo virtuale, usa in qualche maniera un membro della classe) e subito si rompe, può anche indurre l'ottimizzatore a fare assunzioni errate riguardo al tuo codice.

    A tal proposito (e in generale, a proposito dei pericoli dell'undefined behavior) consiglio di dare un'occhiata a qualche articolo:
    http://blog.llvm.org/2011/05/what-ev...ould-know.html
    http://blog.llvm.org/2011/05/what-ev...d-know_14.html
    http://blog.llvm.org/2011/05/what-ev...d-know_21.html
    (più magari questa serie come introduzione:
    http://blog.regehr.org/archives/213
    http://blog.regehr.org/archives/226
    http://blog.regehr.org/archives/232)
    Ultima modifica di MItaly; 13-10-2014 a 01:07
    Amaro C++, il gusto pieno dell'undefined behavior.

  3. #3
    Utente di HTML.it L'avatar di gaten
    Registrato dal
    Jul 2007
    Messaggi
    1,269
    Si ma la la cosa eclatante è che test non è static, per cui necessita di un istanza per essere richiamato e qui invece pure null va bene ... dunque verificare prima se è diverso da null e poi richiamare il metodo è corretto.
    Con i sogni possiamo conoscere il futuro...

  4. #4
    Quote Originariamente inviata da gaten Visualizza il messaggio
    Si ma la la cosa eclatante è che test non è static, per cui necessita di un istanza per essere richiamato e qui invece pure null va bene ...
    Nominalmente gli hai dato un puntatore ad un'istanza - che poi non sia un'istanza valida (e che per casi strani non faccia una piega neanche a runtime) è un altro paio di maniche.
    dunque verificare prima se è diverso da null e poi richiamare il metodo è corretto.
    Sì; in alternativa, come detto sopra, puoi sollevare un'eccezione (che risale lo stack e, tra le altre cose, evita che venga eseguita la chiamata al metodo).
    Amaro C++, il gusto pieno dell'undefined behavior.

  5. #5
    Utente di HTML.it L'avatar di gaten
    Registrato dal
    Jul 2007
    Messaggi
    1,269
    Posso capirlo a compile time perchè non da errore ma non capisco proprio perchè non da errore a run-time.
    Inoltre approfitto per chiederti questa cosa.
    Ho il file Entity.h:

    codice:
    #include <string>
    #include <map>
    #include <iostream>
    #include <typeindex>
    #include "IComponent.h"
    
    
    using namespace std;
    
    
    class Entity {
    	public:
    		template <class T> void addComponent(){
    			T *newComponent = new T();
    
    
    			this->mComponents[type_index(typeid(T))] = newComponent;
    			//this->mComponents.insert(pair<type_index, T*>(type_index(typeid(T)), newComponent));
    			newComponent->entity = this;
    			newComponent->init();
    		}
    
    
    
    
    
    
    		template <class T> T* getComponent(){
    			map<type_index, IComponent*>::iterator it =
    				this->mComponents.find(type_index(typeid(T)));
    			if (it != this->mComponents.end())
    				return static_cast<T*>(it->second);
    			else
    				return NULL;
    		}
    
    
    
    
    		void removeComponent(string name, IComponent *Component);
    		
    		
    		bool HasComponent(int eID);
    
    
    
    
    		//void fetchComponents();
    		map<type_index, IComponent*> mComponents;
    	private:
    		// Entity ID
    		int eID;
    		// riferimento a tutti i componenti
    		//map<type_index, IComponent*> mComponents;
    };
    come puoi notare ho implementato direttamente ne file header i metodi addComponent e getComponent, e l'ho dovuto fare dato che se li implemento in Entity.cpp mi rileva questo errore:

    codice:
     riferimento al simbolo esterno "public: class AI_followTarget * __thiscall Entity::getComponent<class AI_followTarget>(void)" (??$getComponent@VAI_followTarget@@@Entity@@QAEPAVAI_followTarget@@XZ) non risolto nella funzione _main
    Con i sogni possiamo conoscere il futuro...

  6. #6
    Quote Originariamente inviata da gaten Visualizza il messaggio
    Posso capirlo a compile time perchè non da errore ma non capisco proprio perchè non da errore a run-time.
    Perché a runtime non viene fatto alcun controllo sulla validità dell'istanza! Il tuo metodo non accede a nulla dei campi dell'istanza su cui l'hai richiamato, per cui non si accorge neanche del fatto che è stato richiamato su un NULL. Se tu in quel metodo invece avessi provato a leggere/scrivere i campi della classe, allora con ogni probabilità avresti ottenuto un crash. Again: è undefined behavior sostanzialmente per motivi di prestazioni, un po' come il fatto che non c'è alcun controllo sullo sforamento dagli array, sull'overflow di interi, eccetera.
    Inoltre approfitto per chiederti questa cosa.
    Le funzioni/i metodi template devono essere definiti sempre nei .h, dato che ogni volta che vengono istanziati è necessario che il compilatore ne conosca i sorgenti (a differenza di quanto accade per le funzioni "normali", di cui è sufficiente che ci sia il prototipo, che poi viene collegato alla definizione vera e propria in fase di linking).
    Leggi qui per ulteriori dettagli.
    Amaro C++, il gusto pieno dell'undefined behavior.

  7. #7
    Utente di HTML.it L'avatar di gaten
    Registrato dal
    Jul 2007
    Messaggi
    1,269
    Perfetto ora mi è più chiaro. Dunque non gli interessa nemmeno se è un metodo d'istanza affinche non usa un membro della classe.

    Riguardo alla definizione dei metodi template. Se in .h faccio semplicemente:

    Template <class T> void addComponent() .. e implemento il metodo in Entity.cpp non mi da problemi a differenza di getComponent (come puoi vedere dall'errore). Come mai?
    Con i sogni possiamo conoscere il futuro...

  8. #8
    Quote Originariamente inviata da gaten Visualizza il messaggio
    Perfetto ora mi è più chiaro. Dunque non gli interessa nemmeno se è un metodo d'istanza affinche non usa un membro della classe.
    Esatto; ricordati comunque che, anche se in questo caso "per caso" funziona, è comunque un errore nel tuo codice chiamare metodi su istanze non valide.
    Riguardo alla definizione dei metodi template. Se in .h faccio semplicemente:

    Template <class T> void addComponent() .. e implemento il metodo in Entity.cpp non mi da problemi a differenza di getComponent (come puoi vedere dall'errore). Come mai?
    Perché non l'hai richiamato da altri .cpp.
    Amaro C++, il gusto pieno dell'undefined behavior.

  9. #9
    Utente di HTML.it L'avatar di gaten
    Registrato dal
    Jul 2007
    Messaggi
    1,269
    Quote Originariamente inviata da MItaly Visualizza il messaggio
    Esatto; ricordati comunque che, anche se in questo caso "per caso" funziona, è comunque un errore nel tuo codice chiamare metodi su istanze non valide.
    Si, infatti è errore chiamare metodi su istanze non valide, dunque risolvo verificando se è NULL l'elemento ritornato da getComponent. Giusto?
    Con i sogni possiamo conoscere il futuro...

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2026 vBulletin Solutions, Inc. All rights reserved.