How to initialize private static members in C++?

后端 未结 17 2293
忘掉有多难
忘掉有多难 2020-11-21 07:04

What is the best way to initialize a private, static data member in C++? I tried this in my header file, but it gives me weird linker errors:

class foo
{
           


        
相关标签:
17条回答
  • 2020-11-21 07:18

    Since C++17, static members may be defined in the header with the inline keyword.

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

    "A static data member may be declared inline. An inline static data member can be defined in the class definition and may specify a default member initializer. It does not need an out-of-class definition:"

    struct X
    {
        inline static int n = 1;
    };
    
    0 讨论(0)
  • 2020-11-21 07:18

    With a Microsoft compiler[1], static variables that are not int-like can also be defined in a header file, but outside of the class declaration, using the Microsoft specific __declspec(selectany).

    class A
    {
        static B b;
    }
    
    __declspec(selectany) A::b;
    

    Note that I'm not saying this is good, I just say it can be done.

    [1] These days, more compilers than MSC support __declspec(selectany) - at least gcc and clang. Maybe even more.

    0 讨论(0)
  • 2020-11-21 07:20

    Also working in privateStatic.cpp file :

    #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
    
    0 讨论(0)
  • 2020-11-21 07:22

    I don't have enough rep here to add this as a comment, but IMO it's good style to write your headers with #include guards anyway, which as noted by Paranaix a few hours ago would prevent a multiple-definition error. Unless you're already using a separate CPP file, it's not necessary to use one just to initialize static non-integral members.

    #ifndef FOO_H
    #define FOO_H
    #include "bar.h"
    
    class foo
    {
    private:
        static bar i;
    };
    
    bar foo::i = VALUE;
    #endif
    

    I see no need to use a separate CPP file for this. Sure, you can, but there's no technical reason why you should have to.

    0 讨论(0)
  • 2020-11-21 07:24

    If you want to initialize some compound type (f.e. string) you can do something like that:

    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;
        }
    };
    

    As the ListInitializationGuard is a static variable inside SomeClass::getList() method it will be constructed only once, which means that constructor is called once. This will initialize _list variable to value you need. Any subsequent call to getList will simply return already initialized _list object.

    Of course you have to access _list object always by calling getList() method.

    0 讨论(0)
  • 2020-11-21 07:25

    C++11 static constructor pattern that works for multiple objects

    One idiom was proposed at: https://stackoverflow.com/a/27088552/895245 but here goes a cleaner version that does not require creating a new method per member.

    main.cpp

    #include <cassert>
    #include <vector>
    
    // Normally on the .hpp file.
    class MyClass {
    public:
        static std::vector<int> v, v2;
        static struct StaticConstructor {
            StaticConstructor() {
                v.push_back(1);
                v.push_back(2);
                v2.push_back(3);
                v2.push_back(4);
            }
        } _staticConstructor;
    };
    
    // Normally on the .cpp file.
    std::vector<int> MyClass::v;
    std::vector<int> MyClass::v2;
    // Must come after every static member.
    MyClass::StaticConstructor MyClass::_staticConstructor;
    
    int main() {
        assert(MyClass::v[0] == 1);
        assert(MyClass::v[1] == 2);
        assert(MyClass::v2[0] == 3);
        assert(MyClass::v2[1] == 4);
    }
    

    GitHub upstream.

    Compile and run:

    g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o main.out main.cpp
    ./main.out
    

    See also: static constructors in C++? I need to initialize private static objects

    Tested on Ubuntu 19.04.

    C++17 inline variable

    Mentioned at: https://stackoverflow.com/a/45062055/895245 but here is a multifile runnable example to make it even clearer: How do inline variables work?

    0 讨论(0)
提交回复
热议问题