10.2 Clang: global static class Instanz



  • Hallo zusammen,

    folgender Code funktioniert (tut was ich erwarte) im klassischen Compiler, jedoch nicht im Clang.

    Die folgende Klasse soll Lizenzinformationen von verschiedenen Bibliotheken in einem Vector speichern, damit diese später angezeigt werden können.

    #define KC_LIC_DERIVED(NAME_WITHOUT_T_, LIC_STRING_)  \
    class T##NAME_WITHOUT_T_ : public TkcLic              \
    {                                                     \
    public:                                               \
        T##NAME_WITHOUT_T_(String s)                      \
        {                                                 \
            static bool bAdded = false;                   \
            static String sLicense = s;                   \
                                                          \
            addInfos(&sLicense, bAdded);                  \
        };                                                \
    };                                                    \
                                                          \
    static T##NAME_WITHOUT_T_ NAME_WITHOUT_T_(LIC_STRING_);
    
    class TkcLic
    {
    private:
        ///the one and only which hold the license info pointers
        static std::vector<String*>licInfos_vec;
    
    protected:
        void addInfos(const String *sInfo, bool &bAdded)
        {
            if(bAdded)
            {
                return;
            }
            licInfos_vec.push_back((String *)sInfo);
            bAdded = true;
        }
    
    public:
        static int getCount(void) {return licInfos_vec.size();};
        static String* getLic(int i) {return licInfos_vec.at(i);};
    
        TkcLic() {}
        ~TkcLic() {}
    };
    
    ///the one and only which hold the license info pointers
    std::vector<String*>TkcLic::licInfos_vec;
    

    Das Macro wird wie folgt verwendet um eine Lizenz in der Klasse zu speichern.
    Mir ist bewusst, daß sich dies sicherlich schöner als mit einem Macro realisieren lässt.

    KC_LIC_DERIVED(sqliteLic,  L"ich bin die Lizenz");
    

    Was ich nun festgestellt habe, ist daß Informationen fehlen, genauer gesagt ist immer nur ein Eintrag im Vector (eventuell auch Zufall).
    Die erste Frage ist, ist die Implementierung soweit richtig?
    Zweite Frage, hat jemand schon mal etwas ähnliches beobachtet?
    Ich vermute, daß warum auch immer die static Instanz des licInfos_vec mehrfach initialisiert wird.

    Vielen Dank im Voraus.
    MfG Stephan



  • In welcher Datei hast du die Definition des statischen Vectors 'licInfos_vec' stehen? Diese muß in einer getrennten ÜE (CPP-Datei) stehen, nicht im Header!



  • Th69 schrieb:

    In welcher Datei hast du die Definition des statischen Vectors 'licInfos_vec' stehen? Diese muß in einer getrennten ÜE (CPP-Datei) stehen, nicht im Header!

    Daran habe ich mittlerweile auch gedacht.
    Dadurch wird es etwas besser (es fehlen weniger Einträge), aber richtigen funktionieren tut es immer noch nicht.

    MfG Stephan



  • Also, wenn std::vector<String*>TkcLic::licInfos_vec im Header steht funktioniert es im klassischen Compiler.
    Verschiebe ich es in die CPP Datei (so wie es meiner Meinung nach richtig ist) fehlen mir im Clang und klassischen Compiler Einträge.

    Bin etwas irritiert.

    MfG Stephan



  • Nachdem bAdded auf true gesetzt wurde, werden Stringzeiger bei nachfolgenden Aufrufen von addInfo logischerweise nicht zur Liste hinzugefügt. Warum eigentlich dieses merkwürdige Ableiten und das Makro, wenn du doch einfach nur ne Normale Liste brauchst, der du etwas anfügst?



  • Techel schrieb:

    Nachdem bAdded auf true gesetzt wurde, werden Stringzeiger bei nachfolgenden Aufrufen von addInfo logischerweise nicht zur Liste hinzugefügt.

    Das ist vollkommen richtig, gewollt und nicht das Problem.
    Das Problem ist ziemlich sicher, daß std::vector<String*>TkcLic::licInfos_vec mehrfach initialisiert wird.

    Techel schrieb:

    Warum eigentlich dieses merkwürdige Ableiten und das Makro, wenn du doch einfach nur ne Normale Liste brauchst, der du etwas anfügst?

    Jede durch das Makro abgeleitet Klasse kann/darf ihren String genau ein Mal in die Liste eintragen. Um nicht mehrfach den gleichen String in der Liste zu haben gibt es das bAdded Flag.

    Ich hoffe der Sinn ist soweit klar, wenn nicht nochmals Fragen.
    Vielleicht denke ich momentan auch viel zu kompliziert.

    MfG Stephan



  • Stephan schrieb:

    ... Um nicht mehrfach den gleichen String in der Liste zu haben gibt es das bAdded Flag.

    ...

    Dann nimm doch einfach eine Map mit dem String als Schlüssel:

    std::map<String,bool> Licmap;
    
    ....
    if (Licmap.count(sInfo) == 0) Licmap[sInfo]=true;
    ...
    

    Nachtrag 03.08.2017: Selbst das if würde nicht unbedingt benötigt werden:

    ...
    Licmap[sInfo]=true;
    ....
    


  • Burkhi schrieb:

    Dann nimm doch einfach eine Map mit dem String als Schlüssel:

    Werde ich versuchen, jedoch vermutlich habe ich damit ähnliche Probleme, da ich hier ja auch eine einzige globale Instanz benötige um alle Strings zu sammeln.

    MfG Stephan



  • Mein Problem hat vermutlich etwas mit der willkürlichen Initialisierung von Variablen zu tun.
    Das ganze ist auch hier beschrieben: https://isocpp.org/wiki/faq/ctors#static-init-order

    Zur Lösung habe ich mir eine Funktion gebaut wie im Abschnitt How do I prevent the “static initialization order fiasco”? beschrieben.
    Zusätzlich habe ich wie von Burkhi empfohlen eine std::map zu verwenden.

    MfG Stephan



  • Burkhi schrieb:

    Nachtrag 03.08.2017: Selbst das if würde nicht unbedingt benötigt werden:

    ...
    Licmap[sInfo]=true;
    ....
    

    Warum dann nicht gleich ein Set?

    std::set<String> licmap;
    ...
    licmap.insert(sInfo);
    

Anmelden zum Antworten