data - c++ static member inline



Wie initialisiert man private statische Mitglieder in C++? (11)

Auch in der Datei privateStatic.cpp funktioniert:

#include <iostream>

using namespace std;

class A
{
private:
  static int v;
};

int A::v = 10; // possible initializing

int main()
{
A a;
//cout << A::v << endl; // no access because of private scope
return 0;
}

// g++ privateStatic.cpp -o privateStatic && ./privateStatic

https://ffff65535.com

Was ist der beste Weg, um einen privaten, statischen Datenmember in C ++ zu initialisieren? Ich habe das in meiner Header-Datei versucht, aber es gibt mir seltsame Linker-Fehler:

class foo
{
    private:
        static int i;
};

int foo::i = 0;

Ich vermute, das liegt daran, dass ich ein privates Mitglied außerhalb der Klasse nicht initialisieren kann. Also, was ist der beste Weg, dies zu tun?


Das Linker-Problem, auf das Sie stießen, wird wahrscheinlich verursacht durch:

  • Bereitstellung der Definition für Klassen und statische Elemente in der Header-Datei
  • Einbeziehen dieses Headers in zwei oder mehr Quelldateien.

Dies ist ein häufiges Problem für diejenigen, die mit C ++ beginnen. Statisches Klassenmitglied muss in einer einzelnen Übersetzungseinheit, dh in einer einzelnen Quelldatei, initialisiert werden.

Leider muss das statische Klassenmitglied außerhalb des Klassenkörpers initialisiert werden. Dies erschwert das Schreiben von Nur-Kopf-Code, und daher verwende ich einen ganz anderen Ansatz. Sie können Ihr statisches Objekt über eine statische oder nicht statische Klassenfunktion bereitstellen, zum Beispiel:

class Foo
{
    // int& getObjectInstance() const {
    static int& getObjectInstance() {
        static int object;
        return object;
    }

    void func() {
        int &object = getValueInstance();
        object += 5;
    }
};

Eignet sich das für Ihren Zweck?

//header file

struct MyStruct {
public:
    const std::unordered_map<std::string, uint32_t> str_to_int{
        { "a", 1 },
        { "b", 2 },
        ...
        { "z", 26 }
    };
    const std::unordered_map<int , std::string> int_to_str{
        { 1, "a" },
        { 2, "b" },
        ...
        { 26, "z" }
    };
    std::string some_string = "justanotherstring";  
    uint32_t some_int = 42;

    static MyStruct & Singleton() {
        static MyStruct instance;
        return instance;
    }
private:
    MyStruct() {};
};

//Usage in cpp file
int main(){
    std::cout<<MyStruct::Singleton().some_string<<std::endl;
    std::cout<<MyStruct::Singleton().some_int<<std::endl;
    return 0;
}

Für eine Variable :

foo.h:

class foo
{
private:
    static int i;
};

foo.cpp:

int foo::i = 0;

Dies liegt daran, dass es in Ihrem Programm nur eine Instanz von foo::i kann. Es ist eine Art Entsprechung von extern int i in einer Header-Datei und int i in einer Quelldatei.

Für eine Konstante können Sie den Wert direkt in die Klassendeklaration einfügen:

class foo
{
private:
    static int i;
    const static int a = 42;
};

Ich folge der Idee von Karl. Ich mag es und jetzt benutze ich es auch. Ich habe ein bisschen die Notation geändert und etwas Funktionalität hinzugefügt

#include <stdio.h>

class Foo
{
   public:

     int   GetMyStaticValue () const {  return MyStatic();  }
     int & GetMyStaticVar ()         {  return MyStatic();  }
     static bool isMyStatic (int & num) {  return & num == & MyStatic(); }

   private:

      static int & MyStatic ()
      {
         static int mStatic = 7;
         return mStatic;
      }
};

int main (int, char **)
{
   Foo obj;

   printf ("mystatic value %d\n", obj.GetMyStaticValue());
   obj.GetMyStaticVar () = 3;
   printf ("mystatic value %d\n", obj.GetMyStaticValue());

   int valMyS = obj.GetMyStaticVar ();
   int & iPtr1 = obj.GetMyStaticVar ();
   int & iPtr2 = valMyS;

   printf ("is my static %d %d\n", Foo::isMyStatic(iPtr1), Foo::isMyStatic(iPtr2));
}

dies gibt aus

mystatic value 7
mystatic value 3
is my static 1 0

Ich habe nicht genug rep hier, um dies als Kommentar hinzuzufügen, aber IMO ist es gut Stil, Ihre Header mit #include Guards sowieso zu schreiben, die, wie von Paranaix vor ein paar Stunden festgestellt, würde eine Multiple-Definition-Fehler verhindern. Sofern Sie nicht bereits eine separate CPP-Datei verwenden, ist es nicht notwendig, nur eine zu verwenden, um statische nicht-integrale Elemente zu initialisieren.

#ifndef FOO_H
#define FOO_H
#include "bar.h"

class foo
{
private:
    static bar i;
};

bar foo::i = VALUE;
#endif

Ich sehe keine Notwendigkeit, eine separate CPP-Datei dafür zu verwenden. Sicher, das kannst du, aber es gibt keinen technischen Grund, warum du es tun solltest.


Mit einem Microsoft-Compiler [1] können statische Variablen, die nicht int like sind, auch in einer Header-Datei, aber außerhalb der Klassendeklaration mit dem Microsoft-spezifischen __declspec(selectany) .

class A
{
    static B b;
}

__declspec(selectany) A::b;

Beachten Sie, dass ich nicht sage, dass das gut ist, ich sage nur, dass es getan werden kann.

[1] __declspec(selectany) unterstützen mehr Compiler als MSC __declspec(selectany) - zumindest gcc und clang. Vielleicht sogar mehr.


Seit C ++ 17 können statische Member im Header mit dem Inline- Schlüsselwort definiert werden.

http://en.cppreference.com/w/cpp/language/static

Ein statisches Datenelement kann inline deklariert werden. Ein inline statisches Datenelement kann in der Klassendefinition definiert werden und kann einen standardmäßigen Elementinitialisierer angeben. Es benötigt keine Definition außerhalb der Klasse:

struct X
{
    inline static int n = 1;
};

Was ist mit einer Methode set_default() ?

class foo
{
    public:
        static void set_default(int);
    private:
        static int i;
};

void foo::set_default(int x) {
    i = x;
}

Wir müssten nur die Methode set_default(int x) verwenden und unsere static Variable würde initialisiert werden.

Dies würde nicht im Widerspruch zu den übrigen Kommentaren stehen, tatsächlich folgt es dem gleichen Prinzip der Initialisierung der Variablen in einem globalen Umfang, aber indem wir diese Methode verwenden, machen wir sie explizit (und leicht zu verstehen) anstatt die Definition zu haben der Variable hängt dort.


Wenn Sie einen zusammengesetzten Typ (zB String) initialisieren möchten, können Sie Folgendes tun:

class SomeClass {
  static std::list<string> _list;

  public:
    static const std::list<string>& getList() {
      struct Initializer {
         Initializer() {
           // Here you may want to put mutex
           _list.push_back("FIRST");
           _list.push_back("SECOND");
           ....
         }
      }
      static Initializer ListInitializationGuard;
      return _list;
    }
};

Da der ListInitializationGuard eine statische Variable innerhalb der SomeClass::getList() -Methode ist, wird er nur einmal konstruiert, was bedeutet, dass der Konstruktor einmal aufgerufen wird. Dies initialize _list Variable initialize _list auf den von Ihnen benötigten Wert. Jeder nachfolgende Aufruf von getList wird einfach das bereits initialisierte _list -Objekt zurückgeben.

Natürlich müssen Sie immer auf das _list Objekt zugreifen, indem Sie die getList() Methode aufrufen.


int foo::i = 0; 

Ist die richtige Syntax für die Initialisierung der Variablen, aber es muss in der Quelldatei (.cpp) und nicht in der Kopfzeile gehen.

Da es sich um eine statische Variable handelt, muss der Compiler nur eine Kopie davon erstellen. Sie müssen eine Zeile "int foo: i" irgendwo in Ihrem Code haben, um dem Compiler mitzuteilen, wo Sie es setzen müssen, sonst erhalten Sie einen Link-Fehler. Wenn das in einem Header ist, erhalten Sie eine Kopie in jeder Datei, die den Header enthält, also erhalten Sie mehrfach definierte Symbolfehler vom Linker.





static-members