Problem mit statischen Klassenelementen



  • freak11 schrieb:

    Jester schrieb:

    Du mußt die Variable auch noch definieren, im Header steht nur die Deklaration.

    Definition und Deklaration sind bei int Variablen das Gleiche. In der Klasse steht auch eine Definition.

    Eine Definition reserviert auch den benötigten Speicher.

    extern int x; ist übrigens eine Deklaration und keine Definition. Es ist ergo nicht das gleiche.



  • Eine "Klasse" die ausschliesslich aus statischen Daten-Members und statischen Memberfunktionen besteht ist IMHO keine Klasse sondern eine Abschäulichkeit. Dazu gibt es seit Annbeginn der Zeit Funktionen. Pack sie in einen Namespace und gut.

    Dein Ansatz hat im Übrigen auch mit Objektorientierung IMO nichts zu tun.



  • hustbaer schrieb:

    Eine "Klasse" die ausschliesslich aus statischen Daten-Members und statischen Memberfunktionen besteht ist IMHO keine Klasse sondern eine Abschäulichkeit. Dazu gibt es seit Annbeginn der Zeit Funktionen. Pack sie in einen Namespace und gut.

    Dein Ansatz hat im Übrigen auch mit Objektorientierung IMO nichts zu tun.

    ..und ein Singleton scheint mir durchaus Sinnvoll in dieser Situation.
    Du nennst die Klasse ja schon "Kontrollklasse", - wie oft sieht man ein "...Manager" als Klassennamen für Signeltons?

    Was genau hast du mit deinem Konstrukt eigentlich vor? Wenn es sich, wie der Name andeutet, um eine Verwalterklasse oder eine Fassade handeln sollte, sprich einfach einer Klasse mit nur einer Instanz UND einem globalen Zugriffspunkt, dann ist das Singleton Pattern miho das richtige für dich.

    Aber ich bin gespannt was du noch vor hast mit der Klasse..



  • Nun, den Ansatz mit den statischen Daten gibt es ja schon. Siehe Monostate bzw. Borg-Pattern
    und hier
    http://www.informit.com/guides/content.asp?g=cplusplus&seqNum=147&rl=1



  • Mir ist durchaus bewusst dass dies kein "richtiges" objektorientiertes Klassenmodell ist, sondern nur eine Art Namespace-Kapselung mit privaten Datenelementen.

    Ein Singleton ist meiner Meinung nach absolut unnötig, da jedes Objekt sowieso die gleichen Daten beinhaltet.
    Ich rufe die Methoden (oder korrekter gesagt Funktionen) der Klasse mehrere hundert Tausend Mal pro Sekunde auf.
    Da spielt es schon eine Rolle dass die Zugriffsmethoden eines Singletons mit Instanzvariablen nicht inlined sein können und ich jedes Mal den this-Zeiger der Singleton-Instanz holen muss.

    Meint ihr dass dies nicht Grund genug ist, und man auch in diesem speziellen Fall konsequent objektorientiert vorgehen soll?

    Vielen Dank für Eure Ratschläge!



  • Achja, die Deklaration und Definition des Konstruktors und Destruktors wie im Beispiel gezeigt ist natürlich unnötig, da eh keine Instanzen erzeugt werden sollten.



  • Senfgurke schrieb:

    Mir ist durchaus bewusst dass dies kein "richtiges" objektorientiertes Klassenmodell ist, sondern nur eine Art Namespace-Kapselung mit privaten Datenelementen.

    Wieso nimmst du nicht gleich einen Namespace dafür, anstatt eine class zweckzuentfremden?



  • CStoll schrieb:

    Wieso nimmst du nicht gleich einen Namespace dafür, anstatt eine class zweckzuentfremden?

    Weil ich die Klassenvariablen als private deklarieren kann.



  • Wenn's dir nur um die Datenkapselung geht, kannst du die Variablen auch hinter einem anonymen Namensraum verstecken.



  • CStoll schrieb:

    Wenn's dir nur um die Datenkapselung geht, kannst du die Variablen auch hinter einem anonymen Namensraum verstecken.

    Fu.h

    namespace Fu
    {
    	inline void bar();
    }
    

    Fu.cpp

    namespace
    {
    	int privat;
    }
    
    void Fu::bar()
    {
    	privat = 0;
    }
    

    Nutzer.cpp

    #include "Fu.h"
    	...
    	Fu::bar();
    	...
    

    Da kann der Linker die Funktion nicht auflösen.
    Ohne inline-Deklaration kann er es.



  • Hmm, hat jemand eine Idee warum der Linker da Probleme hat?



  • Auch wenn ich int privat in der .cpp auserhalb des anonymen Namensbereich deklariere und definiere kann der Linker die Funktion nicht auflösen.
    Hmm...



  • Senfgurke schrieb:

    Auch wenn ich int privat in der .cpp auserhalb des anonymen Namensbereich deklariere und definiere kann der Linker die Funktion nicht auflösen.
    Hmm...

    Hast du den Namespace in der Cpp datei vor den Funktionsnamen gepackt?



  • Erstens solltest du das "inline" nur angeben, wenn du die Funktion direkt im Header implementierst (damit sagst du dem Compiler, daß er den Funktionsinhalt direkt einkopieren soll statt einen Funktionsaufruf zu erzeugen - also bereitet er auch nichts für einen Funktionsaufruf vor, wenn es nicht nötig ist). Und zweitens ist es vermutlich besser, du öffnest im CPP auch den Namensraum:

    //foo.h
    namespace foo
    {
      void bar();
    }
    
    //foo.cpp
    #include "foo.h"
    namespace foo
    {
      namespace
      {
        int privat;
      }
    
      void bar()
      {
        privat = 4711;
      }
    }
    


  • Danke für die Vorschläge.

    CStoll schrieb:

    Erstens solltest du das "inline" nur angeben, wenn du die Funktion direkt im Header implementierst

    Ich glaube dass ist so nicht richtig.
    Gerade wenn ich die Funktion im Header definiere, wird sie implizit als inline deklariert.
    Wenn ich sie außerhalb definiere, muss ich sie manuell mit inline oder __forceinline deklarieren.

    Also wird bar() im Beispiel nicht als inline-Funktion vom Compiler behandelt.

    Vielleicht sollte ich das einfach in C implementieren.



  • Senfgurke schrieb:

    Danke für die Vorschläge.

    CStoll schrieb:

    Erstens solltest du das "inline" nur angeben, wenn du die Funktion direkt im Header implementierst

    Ich glaube dass ist so nicht richtig.
    Gerade wenn ich die Funktion im Header definiere, wird sie implizit als inline deklariert.

    Das ist (sorry) Bullsh**. Der Compiler sieht überhaupt nichts mehr von Headern, deshalb ist es ihm auch egal, ob du eine Funktion im Header oder im CPP-File definiert hast.

    Wenn du eine Funktion im Header definierst, mußt du sie als inline kennzeichnen, sonst könntest du Probleme von Linker bekommen (Mehrfachdefinitionen). Wenn du die Funktion im Header nur deklarierst und im CPP-File definierst, brauchst du kein inline (und wie du selbst gesehen hast, ist es eher hinderlich).

    PS: Und implizit als inline deklariert werden nur Klassenmethoden, die du innerhalb der Klassendefinition gleich definierst.

    PPS: Egal was du machst, die letzte Entscheidung über "inline oder nicht?" trifft in jedem Fall dein Compiler.



  • Stimmt.
    Ich habe im Delirium von Definition im Header gesprochen, obwohl ich die Definition von Klassenmethoden innerhalb der Klassendefinition meinte.

    Mit __forceinline kann ich doch aber den compiler zwingen (wenn es fehlerfrei möglich ist) die Funktion als inline zu behandeln.
    Nur kann ich dass auch in deinem Beispiel nicht umsetzen.



  • Senfgurke schrieb:

    Mit __forceinline kann ich doch aber den compiler zwingen (wenn es fehlerfrei möglich ist) die Funktion als inline zu behandeln.

    Ja, kannst du. Nur gibt es einige Fälle, wo du eine Funktion NICHT inline definieren kannst (und ein Beispiel davon ist, wenn du die Implementation in eine externe CPP-Datei auslagerst).

    Nur kann ich dass auch in deinem Beispiel nicht umsetzen.

    Gut erkannt 😉



  • CStoll schrieb:

    Wenn du die Funktion im Header nur deklarierst und im CPP-File definierst, brauchst du kein inline (und wie du selbst gesehen hast, ist es eher hinderlich).

    Mir ist es trotz geeigneter Compileroption (/Ob2, /Ot) nicht gelungen dass auch bei kleinsten Funktionsinhalten für diesen Fall inline angewandt wird.

    Ist es überhaupt möglich eine Funktion in einem Header zu deklarieren, im Modul zu definieren und als inline in anderen Modulen zu nutzen?
    Kann man Variablen mit interner Bindung in einer Funktion nutzen, welche mit inline in anderen Modulen genutzt wird?

    Vielen Dank für Eure Geduld! 🙂



  • Senfgurke schrieb:

    Mir ist es trotz geeigneter Compileroption (/Ob2, /Ot) nicht gelungen dass auch bei kleinsten Funktionsinhalten für diesen Fall inline angewandt wird.

    Wenn Du das auf den unten geschilderten Fall beziehst wundert mich das nicht.

    Ist es überhaupt möglich eine Funktion in einem Header zu deklarieren, im Modul zu definieren und als inline in anderen Modulen zu nutzen?

    Nein, wie denn auch? Der Compiler kennt in dem Fall (der Benutzung) die Definition der Funktion nicht, er kennt nur den Funktionskopf. Er kann in diesem Fall keine andere Substitution für diesen Aufruf machen, als den tatsächlichen Aufruf. Der Linker fügt für diesen Aufruf dann die tatsächliche Adresse ins Endprodukt ein, aber der Linker macht kein Inlining.


Anmelden zum Antworten