Tracer-Klasse Vorstellung
-
Da es relativ viel Code ist wollte ich hier nicht alles in Tags packen und euch hier zeigen, sondern ich habe das ganze mal hochgeladen, und würde mich echt darüber freuen wenn sich die ein oder anderen Zeit nemen könnten und sich das mal ansehen könnten, und mir nützliche Tips geben kann, wie man was anders machen kann oder was noch dazu machen könnte.
Das ganze ist ein C::B Projekt.
Ansonsten noch einen angenehmen Sonntag Abend.
Edit: Ein wenig Hilfe habe ich aus dem Breymann genommen, naja eigentlich relativ viel, wollte es trotzdem mal vorstellen.
EDIT:
NUMMERIERTESOBJEK_H_INCLUDED.h#ifndef NUMMERIERTESOBJEK_H_INCLUDED #define NUMMERIERTESOBJEK_H_INCLUDED #include<iostream> #include<cstdlib> class NummeriertesObjekt { private: static int anzahl; static unsigned long maxNummer; const unsigned long SerienNr; public: NummeriertesObjekt(); NummeriertesObjekt(const NummeriertesObjekt&); ~NummeriertesObjekt(); unsigned long Seriennummer()const { return SerienNr;} static int Anzahl() {return anzahl;} static bool Testmodus; }; #endif // NUMMERIERTESOBJEK_H_INCLUDEDNUMMERIERTESOBJEK_H_INCLUDED.cpp
#include "NummeriertesObjek.h" int NummeriertesObjekt::anzahl = 0; unsigned long NummeriertesObjekt::maxNummer = 0L; bool NummeriertesObjekt::Testmodus = false; NummeriertesObjekt::NummeriertesObjekt() : SerienNr(++maxNummer) { ++anzahl; if(Testmodus) { if(SerienNr == 1) { std::cout<<"Start der Objekterzeugung"<<std::endl; std::cout<<"Objekt Nr. "<<SerienNr<<" erzeugt."<<std::endl; } } } NummeriertesObjekt::NummeriertesObjekt(const NummeriertesObjekt &numobj) : SerienNr(++maxNummer) { ++anzahl; if(Testmodus) { std::cout<<"Objekt Nr. "<<SerienNr<<" mit Nr. "<<numobj.Seriennummer()<<" erzeugt."<<std::endl; } } NummeriertesObjekt::~NummeriertesObjekt() { --anzahl; if(anzahl < 0) { assert(anzahl >=0); } }TRACER_H_INCLUDED.h
#ifndef TRACER_H_INCLUDED #define TRACER_H_INCLUDED #include <iostream> #include <string> #include <vector> #include "..\NumObj\NummeriertesObjek.h" class Tracer : public NummeriertesObjekt { private: static std::vector<Tracer*> tracervec; const std::string tracename; public: Tracer(const std::string& = ""); Tracer(const Tracer&); Tracer& operator=(const Tracer&); virtual ~Tracer(); const std::string& Objektname() const { return tracename;} static void druckeObjekte(); static void TextEinfuegen(const std::string&); }; #endif // TRACER_H_INCLUDEDTRACER_H_INCLUDED.cpp
#include "Tracer.h" #include <fstream> static std::ofstream tracedatei; std::vector<Tracer*> Tracer::tracervec; Tracer start("Startobjekt"); Tracer::Tracer(const std::string& name) : tracename(name) { if(Anzahl() == 1) { const std::string DATEINAME = "tracer.txt"; tracedatei.open(DATEINAME.c_str()); std::cout<<DATEINAME; if(!tracedatei) { std::cout<<" konnte nicht geoeffnet werden!"<<std::endl; exit(1); } else { std::cout<<" wird erzeugt!"<<std::endl; } } tracervec.push_back(this); tracedatei<<"("<< Seriennummer() <<")"<<tracename<<" erzeugt."<<std::endl; } Tracer::Tracer(const Tracer& original) : tracename(original.tracename) { tracervec.push_back(this); tracedatei<<"("<< Seriennummer() <<")"<<tracename<<" erzeugt(Kopierkonstruktor)."<<std::endl; } Tracer::~Tracer() { std::vector<Tracer*>::iterator pos = tracervec.begin(); while(pos != tracervec.end() && *pos != this) { ++pos; } if(pos == tracervec.end()) { tracedatei <<"Abbruch! 'delete' auf nicht-existentes Objekt"<<std::endl; tracedatei.close(); exit(2); } else { tracervec.erase(pos); tracedatei<<"("<<Seriennummer()<<")"<<tracename<<" geloescht."<<std::endl; } if(Seriennummer() == 1) { if(tracervec.size() == 0) { tracedatei<<"Objektbilanz OK. Ende Protokollierung"<<std::endl; } else { tracedatei<<"Warnung! Fehlendes 'delete' fuer "; druckeObjekte(); } } } void Tracer::druckeObjekte() { std::vector<Tracer*>::iterator pos = tracervec.begin(); if(tracervec.size() == 1) { tracedatei<<"1 existierendes Objekt."<<std::endl; } else { tracedatei<<tracervec.size()<<" existierende Obejkte: "<<std::endl; while(pos != tracervec.end()) { tracedatei<<"("<<(*pos)->Seriennummer()<<")"<<(*pos)->Objektname()<<std::endl; ++pos; } } } Tracer& Tracer::operator=(const Tracer&) { return *this; } void Tracer::TextEinfuegen(const std::string& text) { tracedatei<<text<<std::endl; }main.cpp
#include <iostream> #include "Tracer.h" using namespace std; class BasisklasseA : virtual public Tracer { public: BasisklasseA() :Tracer("BasisklasseA") {} }; class BasisklasseB : virtual public Tracer { public: BasisklasseB() :Tracer("BasisklasseB"){} }; int main() { BasisklasseA A1; BasisklasseA A2; BasisklasseB *pB = new BasisklasseB; delete pB; return 0; }soo hoffe das ist alles

Ausgabe einer protokolldatei könnte so aussehen.(1)Startobjekt erzeugt.
(2)BasisklasseA erzeugt.
(3)BasisklasseA erzeugt.
(4)BasisklasseB erzeugt.
(4)BasisklasseB geloescht.
(3)BasisklasseA geloescht.
(2)BasisklasseA geloescht.
(1)Startobjekt geloescht.
Objektbilanz OK. Ende Protokollierung
-
Firefighter schrieb:
und sich das mal ansehen könnten, und mir nützliche Tips geben kann, wie man was anders machen kann oder was noch dazu machen könnte.
Du könntest das in der Programmiersprache D lösen.
D löst nämlich alle deine Probleme.
-
C++ nutze ich nicht mehr schrieb:
Firefighter schrieb:
und sich das mal ansehen könnten, und mir nützliche Tips geben kann, wie man was anders machen kann oder was noch dazu machen könnte.
Du könntest das in der Programmiersprache D lösen.
D löst nämlich alle deine Probleme.Also ich habe keine Probleme

@topic: Was macht eine Tracer Klasse?

-
Dies Tracer Klasse soll das erstellen und Löschen von Objekten mitprotokollieren und dich gegenfals darauf hinweisen wenn du versuchst zu viel zu deleten oder dir zum beispiel ein Delete fehlt, eine Beispiel tracerprotokoll datei liegt schon im projekt dabei, kann als eingesehen werden um mal reinzuschnuppern wie die protokollierung ungefähr aussieht. Ich habe leider bei der protokollierung von zu vielen Deletes noch ein problem, jedoch kam ich da nicht weiter und dachte von euch Rat zu erhalten.
-
C++ nutze ich nicht mehr schrieb:
Firefighter schrieb:
und sich das mal ansehen könnten, und mir nützliche Tips geben kann, wie man was anders machen kann oder was noch dazu machen könnte.
Du könntest das in der Programmiersprache D lösen.
D löst nämlich alle deine Probleme.Problem hat man dann, wenn man nichts zu Essen oder kein Dach über den Kopf hat. Dann hat man ein Problem! Aber nicht wenn man sich eine Tracer-Klasse schreibt.
-
Ohne aufdringlich zu wirken
Aber ich würde mich über konstruktive Kritik freuen, bzw über hilfreiche Tips.
-
Dann stell' den Code mal anständig zur Verfügung

-
Das habe ich extra nicht gemacht weil ich dachte es wäre einfach zu viel, aber ok wenn ihr meint mache ich es mal:)
-
Nun steht der Code zur verfügung, ich uppe zwar sehr ungerne, aber ich wollte eure Meinung dazu hören, danke im voraus

-
soll das viel code sein?
meine projekte hatten schon 10000 /100000 und mehr zeilen, ohne abstände natürlich und ohne geschwungene klammern in die nächste zeilen so wie du.
"pff viel code mag nicht reintun mit den klammern in zeilenanfängen"
WoW rockt
-
Oh, da kann ne Menge zu sagen:
NummeriertesObjekt:
if(Testmodus)würde ich nicht machen. Benutz' stattdessen zB den Präprozessor mit NDEBUG (also baue eine Variante zum Debuggen und eine für das fertige Programm).
Inkludiere nur dort, wo es sein muss.#include <iostream>und#include <cstdlib>gehören in die Implementierungsdatei. Dort fehlt auch noch#include <cassert>.
Das assert hast du falsch verwendet, schau dir nochmal dessen Semantik an.Tracer:
Benutze '/' als Pfadtrenner. Das ist meines Wissens portabler (läuft auch unter Windows, ob \ unter Unices funktioniert kann ich grad nicht sagen).
Warum hat Tracer einen virtuellen Destruktor? Du solltest diesen Overhead dem Anwender nur aufzwingen, wenn du tatsächlich auch virtuelle Funktionen benutzt. Tust du aber nicht. Von einer solchen Klasse sollte eh nicht öffentlich geerbt werden.
Benutze im Destruktor std::find um this zu finden statt deiner selbst gebauten Lösung.Generell sind ein paar Sachen designtechnisch nicht so glücklich. Du solltest z.B. Ausgabe nicht zwingend durch std::cout schicken, genauso wenig wie zwingend in eine Datei. Benutz ostream-Referenzen dafür und wie gesagt sollte von Tracer und NummeriertesObjekt höchstens protected geerbt werden.
-
.filmor schrieb:
Benutze '/' als Pfadtrenner. Das ist meines Wissens portabler (läuft auch unter Windows, ob \ unter Unices funktioniert kann ich grad nicht sagen).
das möchte ich unterstreichen. der backslash funktioniert definitiv nicht unter unixoiden. und ich glaube (hoffe), dass microsoft sich von dem backslash in einem der nächsten windows-dateisysteme abwendet.
-
Warum sollte sich Microsoft denn den Unix-Systemen anpassen? Außerdem ist der Pfadtrenner bei Windows auch noch Länderspezifisch. Bei einem japanischen Windows ist es z.Bsp. das Yen-Zeichen.

-
Braunstein schrieb:
Warum sollte sich Microsoft denn den Unix-Systemen anpassen? Außerdem ist der Pfadtrenner bei Windows auch noch Länderspezifisch. Bei einem japanischen Windows ist es z.Bsp. das Yen-Zeichen.

weil es mir als entwickler dann weniger kopfschmerzen bereitet
-
Das ist ein gutes Argument.

Wir können ja mal eine Petition an Microsoft schicken. Das mit dem Yen-Zeichen hatte mir auch einiges an Arbeit eingebracht.
-
Braunstein schrieb:
Das ist ein gutes Argument.

Wir können ja mal eine Petition an Microsoft schicken. Das mit dem Yen-Zeichen hatte mir auch einiges an Arbeit eingebracht.ich glaube das wird nix helfen

-
Wie ich schon in einem Interview bekannt gab habe sogar ich mich von Windows abgewendet, ist einfach ein ewiges rumgekrampfe.
Ich finde die Tracer-Klasse so eher weniger nützlich, da sie nur sehr wenige Informationen bereit stellt, wenn ich Probleme haben mit dem Lebenszyklen von Objekten, dann brauche ich eigentlich immer noch zusätzlich ein Stacktrace und mehrere Checkpoints an kritischen Stellen um zu wissen wo gerade wie verzweigt wurde, sonst weiß ich ja nachher gar nicht wo etwas schief gegangen ist.
Einfach den Speicher nach Leaks zu überwachen bietet ja inzwischen jeder Compiler im Debug-Modus an, ebenso Speicherchecks (also Index-Out-Of-Bounds oder Off-By-One Fehler).
Am angenehmsten unter Windows finde ich das Erstellen eines Minidumps, mit dem enthaltenen Fehler, dann kann man ganz in Ruhe sich hinsetzen und den Fehler analysieren, ist für mich also das ultimative Tracert, wenn man so will.
Falls du Linux benutzt, hast du dir mal strace angesehen, eine Ausgabe wie sie dort erfolgt beinhaltet auch weit mehr Informationen als dein Trace-Tool. Schau dir das mal an und versuch das in deine Bibliothek mitaufzunehmen.
P.S. Ist der Header im ersten Posting die gesamte Trace-Bibliothek?
-
Hey super danke, genauso so eine Kritik brauchte ich, damit kann ich wunderbar weiterarbeiten um das zu verbessern. Andere Frage, würdet ihr noch weitere Funktionen hinzufügen??
@.filmor
Wie meinst du das mit dem "nicht öffentlich geerbt"? Was muss ich da anders machen?
-
Falls dich das Thema interessiert, solltest du dich mal mit aspektorientierter Programmierung befassen. C++ bietet hierfür leider keinen Support (D übrigens genauso wenig). Es gibt allerdings einige Aufsätze wie zB AspectC++. Damit lassen sich Sachen wie Debug-Handling viel sauberer implementieren, weil sie von der eigentlichen Programmlogik getrennt werden.
Bezüglich "nicht öffentlich geerbt", .filmor meint, deine Klasse Tracer ist keine typische Basisklasse, also ist der virtuelle dtor überflüssig. Virtuelle dtors machen ja nur dort Sinn, wo vererbt wird, also die Klasse als Basisklasse benutzt wird, und das öffentlich (public). Wird nicht öffentlich vererbt, kann auf die Instanz der Basisklasse auch nicht zugegriffen werden und non-virtual bietet keine potenzielle Gefahr.
-
Aber wenn ich, angenommen ich mache es, jede meiner neugeschriebenen Klassen von der Tracer Klasse erben lasse ist es dann keine Basisklasse? Oder ist es deswegen keine Basisklasse weil ich in keiner meiner erbenden Klasse eine Methode von der Tracerklasse überschreibe??