Eine Stilfrage



  • mit dme neune standard geht das ja endlich im header



  • standardstil schrieb:

    mit dme neune standard geht das ja endlich im header

    Als ob das besser wäre -.-



  • was ist daran schlechter?



  • unskilled schrieb:

    standardstil schrieb:

    mit dme neune standard geht das ja endlich im header

    Als ob das besser wäre -.-

    Ich habe mir in dem Punkt noch nicht den neuen Standard angeschaut, sehe hier aber kein schlechten Stil. Ansonsten ziehe ich aber Grundsätzlich die Initialisierungsliste vor.

    volkard schrieb:

    ich kenne leute, die machen eigentlich alles in initialisiererlisten. naja, manchmal wirds häßlich.

    Dann kennst du nun noch einen weiteren. Derzeit sehe ich keinen einzigen Grund die Initialisierungsliste (alleine schon aus Konsistenzgründen) nicht für alle Variablen zu verwenden. Hässlich wird das meiner Meinung nach nur wenn die Klasse zuviele Member besitzt (das ist dann aber eher ein Design-, und nicht ein Initialisierungsproblem).

    cu André



  • Initlisten sind schneller, weil der ganzen MeberVar Chunk per MemCopy in die Instanz kopiert wird. Das ist dann nur ein Copy-Befehl.

    Wenn man alle Member einzeln initialisiert, dann wird pro Member einmal kopiert.

    Initialisierungslisten verwendet man für Klassen, von der sehr viele Instanzen erzeugt werden. Weil der Scheiss so schwierig zu lesen ist, sollte man ihn nur verwenden, wenn nötig.

    Typischer Anwendungsfall für Init-Listen: Vektor-Klassen in 3D Anwendungen. Davon hat man oft ein paar tausend Instanzen.



  • Ich verwende sie immer. Der g++ hat 'ne Kompileroption -Weffc++, die warnt, wenn bestimmte Sachen nicht in der Initialisierungsliste des Konstruktors initialisiert werden. Zumal sind die meisten Anfaengerfehler (auch hier im Forum zu beobachten) meist falsche oder nicht initialisierte Variablen.



  • Peter_Lustig schrieb:

    Initlisten sind schneller, weil der ganzen MeberVar Chunk per MemCopy in die Instanz kopiert wird. Das ist dann nur ein Copy-Befehl.
    Wenn man alle Member einzeln initialisiert, dann wird pro Member einmal kopiert.

    wohl kaum.
    unterschiede hats nur, wenn die konstruktoren oder zuweisungsoperatoren teure dinge tun, wie bei std::string.
    attribute vom typ int oder double kannste drch initialisiererlisten nicht beschleunigen.
    entsprechend sind sie auch nur für sachen wie std::string notwendig und alle weitere ist kür.



  • Wie kommste denn darauf?



  • volkard schrieb:

    Peter_Lustig schrieb:

    Initlisten sind schneller, weil der ganzen MeberVar Chunk per MemCopy in die Instanz kopiert wird. Das ist dann nur ein Copy-Befehl.
    Wenn man alle Member einzeln initialisiert, dann wird pro Member einmal kopiert.

    wohl kaum.
    unterschiede hats nur, wenn die konstruktoren oder zuweisungsoperatoren teure dinge tun, wie bei std::string.

    Es mag sein, das es bei integralen Datentypen kaum oder keinen Unterschied macht. Es ist aber meiner Meinung nach schlechter Stil etwas in einem Fall zu machen, in einem Anderen aber nicht. Zumal es zumindest bei mir die Wahrscheinlichkeit reduziert eine Variable zu vergessen (Ich versuche die Initialisierungsliste immer mit den Membern identisch zu halten, die otionale Warnung wie im gcc scheinbar möglich würde ich mir auch bei anderen Compilern wünschen).

    Initialisierungslisten meiner Meinung nach zwar etwas, aber nicht wesentlich, komplizierter zu lesen.

    cu André



  • asc schrieb:

    Initialisierungslisten meiner Meinung nach zwar etwas, aber nicht wesentlich, komplizierter zu lesen.

    Wenn man die Member schön untereinander gliedert, finde ich das nicht mal weniger übersichtlich als Zuweisungen.

    Aus meiner Sicht können Zuweisungen in Ausnahmefällen okay sein (wenn verpätete Initialisierung oder keine Initialisierung aus Performancegründen notwendig ist), aber für die meisten Member sollte man eigentlich Initialisierungslisten verwenden. Zumal es für gewisse Fälle gar keine Alternative gibt.

    standardstil schrieb:

    was ist daran schlechter?

    Das finde ich total schlimm. Keine Ahnung, was sich die Standard-Leute dabei gedacht haben. Als ob es nicht schon genügend Inkonsistenzen und für jedes Problem mehrere sprachliche Ansätze gäbe - nein, man muss jetzt auch noch Member direkt bei der Deklaration initialisieren können. 🙄



  • Habs nachgemessen. Initlisten sind im Release und im Debug Built bei VC 9 (WinXp Professional 2 GB RAM) schneller. Auch bei integralen Datentypen. Der Speedgain betrug bei meinem Benchmark ca. 10% bei diesen 5 Member Vars

    int      m_a;
        double   m_b;
        int      m_c;
        float    m_d;
        unsigned m_e;
    


  • Nexus schrieb:

    standardstil schrieb:

    was ist daran schlechter?

    Das finde ich total schlimm. Keine Ahnung, was sich die Standard-Leute dabei gedacht haben. Als ob es nicht schon genügend Inkonsistenzen und für jedes Problem mehrere sprachliche Ansätze gäbe - nein, man muss jetzt auch noch Member direkt bei der Deklaration initialisieren können. 🙄

    Stimmt, jetzt könnte man diese komischen initialisierungslisten weg werfen, aber dann würden die alten programme nicht mehr funktionieren. Wenn Member schon immer direkt bei der Deklaration initialisiert worden wären und jetzt Initialisierungslisten dazu kommen würden, dann würden alle Initialisierungslisten dämlich finden.



  • standardstil schrieb:

    Wenn Member schon immer direkt bei der Deklaration initialisiert worden wären und jetzt Initialisierungslisten dazu kommen würden, dann würden alle Initialisierungslisten dämlich finden.

    Dir ist aber schon bewusst, dass es mehrere Möglichkeiten gibt, Member einer Klasse zu initialisieren?

    Von daher finde ich die "einheitliche" Initialisierung bei der Deklaration alles andere als gut. Sobald man eine komplexere Klasse hat, hat diese auch mehrere Konstruktoren. Und sobald dies der Fall ist, ist die Initialisierung gleich in der Klassendefinition nicht mehr so einheitlich. Schlussendlich läuft es darauf hinaus, dass gewisse Member in Konstruktoren, gewisse in der Klasse initialisiert werden. Sehr konsistent.



  • Nexus schrieb:

    standardstil schrieb:

    Wenn Member schon immer direkt bei der Deklaration initialisiert worden wären und jetzt Initialisierungslisten dazu kommen würden, dann würden alle Initialisierungslisten dämlich finden.

    Dir ist aber schon bewusst, dass es mehrere Möglichkeiten gibt, Member einer Klasse zu initialisieren?

    Von daher finde ich die "einheitliche" Initialisierung bei der Deklaration alles andere als gut. Sobald man eine komplexere Klasse hat, hat diese auch mehrere Konstruktoren. Und sobald dies der Fall ist, ist die Initialisierung gleich in der Klassendefinition nicht mehr so einheitlich. Schlussendlich läuft es darauf hinaus, dass gewisse Member in Konstruktoren, gewisse in der Klasse initialisiert werden. Sehr konsistent.

    na, wenn du meinst...



  • PeterLustig schrieb:

    Auch bei integralen Datentypen. Der Speedgain betrug bei meinem Benchmark ca. 10%

    aha. 😮
    meine info war aus einem buch. habs geglaubt, ohne selber zu messen.
    ok, dann werd ich wohl mal vermehrt zu initialisiererlisten greifen.



  • volkard schrieb:

    aha. 😮
    meine info war aus einem buch. habs geglaubt, ohne selber zu messen.
    ok, dann werd ich wohl mal vermehrt zu initialisiererlisten greifen.

    Und das passiert Jemanden der aufschreit, wenn einer von vorzeitigen Optimierungen abrät... ;p



  • ich hab da grad was blödes:

    class Console{
    	private:
    	Size sizeX,sizeY;
    	CHAR_INFO* bufferBegin,bufferEnd;
    	CHAR_INFO* lineBegin,lineEnd;
    	CHAR_INFO* pos;
    	public:
    	Console(){
    		HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
    		CONSOLE_SCREEN_BUFFER_INFO csbi;
    		GetConsoleScreenBufferInfo(hConsole,&csbi);
    		sizeX=csbi.dwSize.X;
    		sizeY=csbi.dwSize.Y;
    		bufferBegin=new CHAR_INFO[sizeY*sizeX];
    		bufferEnd=bufferBegin+sizeY*sizeX;
    		lineBegin=bufferBegin;
    		lineEnd=lineBegin+sizeX;
    		pos=lineBegin;
    		//TODO: aktuellen consoleninhalt in den buffer kopieren
    		//cursorposition aus csbi lesen und pos und line* danach 
    		//setzen
    	}
    	void carriageReturn(){
    		pos=lineBegin;
    	}
    	void newLine(){
    		if(lineEnd==bufferEnd){
    			lineBegin=bufferBegin;
    			lineEnd=lineBegin+sizeX;
    			pos-=(sizeY*sizeX-sizeX);
    		}
    		else{
    			lineEnd+=sizeX;
    			lineBegin=lineEnd;
    			pos+=sizeX;
    		}
    		for(CHAR_INFO* p=lineBegin;p!=lineEnd;++p){
    			*p->UnicodeChar=' ';
    			*p->Attributes=7;
    		}
    	}
    	void carriageReturnNewLine(){
    		carriageReturn();
    		newLine();
    	}
    	void writeSpecialChar(char ch){
    	}
    	void writePrintableChar(char ch){
    		*pos=ch;
    		++pos;
    		if(pos==lineEnd)
    			newLine();
    	}
    	void put(char ch){
    		if(ch<16)
    			writeSpecialChar(ch);
    		else
    			writePrintableChar(ch);
    	}
    };
    

    ist alles noch pseudocode, ich experimentiere, wie sich code für eine console anfühlen sollte.

    aber wie mach ich den konstruktor so richtig initialisiererlistenlastig? mir scheint, das würde der ganzen angelegenheit die beine brechen.



  • volkard schrieb:

    ich hab da grad was blödes:
    ...
    aber wie mach ich den konstruktor so richtig initialisiererlistenlastig? mir scheint, das würde der ganzen angelegenheit die beine brechen.

    C-Code in C++ zu wandeln ist nun einmal nicht immer sinnvoll möglich.

    Normalerweise initialisiere ich bei ähnlichen Fällen (aber bei einzelnen Werten) über Rückgabewerte von statische Methoden, da die Initialisierung in so einen Fall eh schon ein Thema für sich ist. Bzw. Kapsel dies in eigene RAII-Objekte.

    Ja, eine einfache Lösung fällt mir hier nicht ein, aber ich muss gestehen das ich zu 95+% mit C++ Schnittstellen hantiere (oder mit Wrappern um eben solche).

    cu André


  • Administrator

    @volkard,
    Kann es überhaupt mehrere Objekt von Console geben? Wäre das nicht perfekt für ein Singleton mit Factory Pattern. In der Fabrikmethode holst du dir ein CONSOLE_SCREEN_BUFFER_INFO und übergibst dieses an den Konstruktor von Console . Dann kann alles in der Initialisierungsliste ausgeführt werden. Wobei man natürlich die Reihenfolge der Initialisierung beachten muss.

    Allerdings lagere ich eigentlich immer gerne Speicherverwaltungsaufgaben aus der Initialisierungsliste raus. Also ein new erfolgt bei mir immer im Konstruktorrumpf und nicht in der Initialisierunsliste.

    Grüssli



  • Dravere schrieb:

    @volkard,
    Kann es überhaupt mehrere Objekt von Console geben?

    bevor deine factory im spiel war, gab es keinen grund dagegen. vielleicht ist es ganz angenehm, ein zweites konsolenfenster für debug-ausgaben oder cerr aufzumachen.

    Wäre das nicht perfekt für ein Singleton mit Factory Pattern. In der Fabrikmethode holst du dir ein CONSOLE_SCREEN_BUFFER_INFO und übergibst dieses an den Konstruktor von Console . Dann kann alles in der Initialisierungsliste ausgeführt werden. Wobei man natürlich die Reihenfolge der Initialisierung beachten muss.

    wenn das nur geschieht, um die initialisiererliste benutzen zu können, ist das nicht ok, finde ich.

    Allerdings lagere ich eigentlich immer gerne Speicherverwaltungsaufgaben aus der Initialisierungsliste raus. Also ein new erfolgt bei mir immer im Konstruktorrumpf und nicht in der Initialisierunsliste.

    jo, geht mir auch so.


Anmelden zum Antworten