Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

22.04.2015, 19:44

Static vector verliert Werte

Hallo alle zusammen,
ich bin gerade dabei, mir eine Log-Klasse zu schreiben. Die Log-Klasse besitzt zwei statische Methoden für eine Info/Error Message. Außerdem kann man sog. 'LogListener' hinzufügen, die die Log-Nachricht als String übergeben kriegen.
Nun musste ich leider feststellen, dass der Vektor, der die LogListener speichern soll, dies nicht tut. Und ich weiß nicht warum. Hier ist mein Code dazu:

C-/C++-Quelltext

1
2
3
4
5
class Log   {   public:     template<typename T> static void Info(const std::string& sText) {           time_t oTime;           time(&oTime);           std::stringstream sStream;          sStream << oTime << " " << typeid(T).name() << " Info: " << sText<<std::endl;
            for (unsigned int i = 0; i < maLogListener.size(); ++i) {               maLogListener[i]->Info(sStream.str());          }       }
        template<typename T> static void Error(const std::string& sText) {          time_t oTime;           time(&oTime);           std::stringstream sStream;          sStream << oTime << " " << typeid(T).name() << " Error: " << sText << std::endl;
            for (unsigned int i = 0; i < maLogListener.size(); ++i) {               maLogListener[i]->Error(sStream.str());         }                   }
        static void addLogListener(ILogListener* pLogListener) {            maLogListener.push_back(pLogListener);      }   private:        static std::vector<ILogListener*> maLogListener;    };


C-/C++-Quelltext

1
class ILogListener {    public:     virtual void Error(const std::string& sError) = 0;      virtual void Info(const std::string& sInfo) = 0;    };



C-/C++-Quelltext

1
2
void Simulation::Error(const std::string& sError) { cerr << sError << endl;}
void Simulation::Info(const std::string& sInfo) {   cout << sInfo << endl;}


(wobei Simulation natürlich von ILogListener public erbt)

Und abschließend in main.cpp:

C-/C++-Quelltext

1
2
Simulation oSimulation;
Log::addLogListener(&oSimulation);


Nach einigem googlen habe ich bereits gelesen, dass es Probleme geben kann, wenn ich die AddLogListener-Methode in einem Konstruktor aufrufe. Hab ich dementsprechend geändert, aber es funktioniert leider trotzdem nicht.

Kann mir einer von euch weiterhelfen?

LG Kyle

Edit: Tut mir Leid, dass der Code so hässlich formatiert ist. Is alles aus VS rauskopiert, wieso geht das nich? :O

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

22.04.2015, 19:47

Du darfst keine Referenzen auf lokale Variablen übergeben. Diese werden beim Verlassen des umschließenden Blocks zerstört! Das führt im Normalfall zu den wildesten Crashes.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

3

22.04.2015, 19:54

Was sagt denn der Debugger ;) Normalerweise tut ein std::vector schon seinen Inhalt speichern. Du solltest in einem Basisklassenkonstruktor keine virtuellen Methoden aufrufen, da der Konstruktor des geerbten Objekt, dessen überschriebene virtuelle Methode aufgerufen wird, noch nicht aufgerufen wurde.

Fireball

Alter Hase

Beiträge: 415

Wohnort: Werne

Beruf: Dipl. Inf.

  • Private Nachricht senden

4

22.04.2015, 22:16

hmm hätte man den code nicht etwas formatieren können? Ich sehe da nämlich gar nichts. :-D

5

23.04.2015, 20:01

@BlueCobold: Du meinst die Zeile, wo ich den Listener hinzufüge? Die Simulation wird direkt in der main erzeugt, existiert als (hfftl) auch bis zum Ende ^^ Oder meinst du ne andere Stelle?

@Roflo: Der Debugger spuckt lustige Sachen aus ... Sobald ich die add-Methode aufrufe hat der Vektor die Größe 1. Wird ne Log-Methode danach aufgerufen, hat der Vektor wieder die Größe 0?!?!?

@Fireball: Ja wie geschrieben tut mir Leid, ich hätte gedacht es geht, wenn ichs direkt aus VS rauskopier ... hab mich wohl geirrt.

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

6

23.04.2015, 20:08

Ohne mehr Code kommen wir hier offensichtlich nicht weiter. Der Fehler steckt sicherlich irgendwo anders und nicht im Vektor an sich.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

7

23.04.2015, 20:48

Ok du hast recht. Ich habe mir gerade eben ein minimalistisches Beispiel zusammen gebastelt, in dem ich den Spaß ausprobiere. Dort geht es.
Vom Code her besteht jedoch kein Unterschied zwischen beiden Projekte.
Das einzige, was mir einfallen würde ist folgendes: Die Log-Klasse wird in einem Projekt Common übersetzt zur einer statischen Bibliothek. Die Header von Common werden wiederum werden im Projekt Simulation verwendet, wo sich die Klasse Simulation befindet, die ja von ILogListener erbt. Das Simulationsprojekt ist ebenfalls eine statische Bibliothek.
'Zusamengebastelt' wird das ganze im Projekt Launcher, wo die main-Methode den Log-Listener zum Log hinzufügt.

Liegt es einfach daran, dass da bei der Reihenfolge irgendwas schief ist und ich da auf mehr achten muss?

Ich würde jetzt ungern den ganzen Code posten, da es doch etwas verschachtelt ist.

Tobiking

1x Rätselkönig

  • Private Nachricht senden

8

23.04.2015, 21:30

Die Header von Common werden wiederum werden im Projekt Simulation verwendet, wo sich die Klasse Simulation befindet, die ja von ILogListener erbt. Das Simulationsprojekt ist ebenfalls eine statische Bibliothek.
'Zusamengebastelt' wird das ganze im Projekt Launcher, wo die main-Methode den Log-Listener zum Log hinzufügt.

Du schießt dir mit dem static + Implementierung im Header selber in den Fuß. Wenn du etwas static deklarierst, wird es vom Linker nicht exportiert. Du könntest in deinem Executable also gar nicht auf die static Teil der Log-Klasse aus der Library zugreifen. Da die Implementierung aber im Header steht, kann in der Executable der static Teil selber erzeugt werden und es compiliert erfolgreich. Ist aber in dem Fall nicht das was du willst.

9

23.04.2015, 22:00

Das heißt ich habe unterschiedliche 'Realisierungen' der Log-Klasse in der Bibliothek und in dem Executable, weil ich die Implementierung im Header habe?
Ich hab dementsprechend versucht, die Implementierung in die Log.cpp zu packen, klappt auch, Ergebnis ist aber dasselbe.

Angenommen ich bau Log zu nem Singleton um, hab ich dann das gleiche Ergebnis?

Tobiking

1x Rätselkönig

  • Private Nachricht senden

10

24.04.2015, 11:11

Ich habs mal etwas nachgelesen. Das mit dem internal linkage, was ich geschrieben hatte, ist wohl nur bei static auf Funktionen und Variablen außerhalb von Klassen. Innerhalb von Klassen beeinflusst es nicht das Linkage, hat aber wohl trotzdem den Effekt, dass die Initialisierung der Klasse in der Lib und der Executable passiert. Entsprechend hast du mehrere std::vector, die sich nicht die Daten teilen.

Ich bin nicht ganz sicher wie sich das ganze auf die Instanz Variable bei dem Singleton auswirkt. Auf globale Objekte kannst du aber problemlos mit einer extern Deklaration zugreifen. Allgemein würde ich dir aber raten zu überlegen ob du wirklich die Log global (dazu zählt auch static und Singleton) brauchst. Gerade über Bibliotheksgrenzen hinaus kann das doppelt hässlich werden.

Werbeanzeige