625

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
{
    private:
        static int i;
};

int foo::i = 0;

I'm guessing this is because I can't initialize a private member from outside the class. So what's the best way to do this?

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
Jason Baker
  • 192,085
  • 135
  • 376
  • 510
  • 4
    Hi Jason. I didn't find a comment on default initialization of static members (esp. integral ones). In fact you need to write int foo::i so that the linker can find it, but it will be automatically initialized with 0! This line would be sufficient: int foo::i; (This is valid for all objects stored in the static memory, the linker is in charge of initializing the static objects.) – Nico Jul 18 '12 at 09:59
  • 2
    The answers below do not apply for a template class. They say: the initialization must go into the source file. For a template class, this is neither possible, nor necessary. – Joachim W Jun 09 '16 at 15:20
  • 14
    C++17 allows inline initialization of static data members (even for non-integer types): `inline static int x[] = {1, 2, 3};`. See http://en.cppreference.com/w/cpp/language/static#Static_data_members – Vladimir Reshetnikov Feb 14 '18 at 21:59

18 Answers18

662

The class declaration should be in the header file, or in the source file, if the class is not used in other files.

// foo.h
class foo
{
    private:
        static int i;
};

However, the initialization should be in the source file.

// foo.cpp
int foo::i = 0;

If the initialization is in the header file, then each file that includes the header file will have a definition of the static member. Thus during the link phase, you will get linker errors as the code to initialize the variable will be defined in multiple source files. The initialization of the static int i must be done outside of any function.

Note: Matt Curtis: points out that C++ allows the simplification of the above if the static data member is of const integer type (bool, char, char8_t [since C++20], char16_t, char32_t, wchar_t, short, int, long, long long, or any implementation-defined extended integer types, including any signed, unsigned, and cv-qualified variants.). You can then declare and initialize the data member directly inside the class declaration in the header file:

class foo
{
    private:
        static int const i = 42;
};
Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 1
    The class declaration can be anywhere – 1800 INFORMATION Oct 09 '08 at 03:37
  • 4
    Yes. But I am assuming the question has been simplified. Technically the declaration and definition can all be in a single source file. But that then limits the use of class by other classes. – Martin York Oct 09 '08 at 03:40
  • I forgot to say that I put them in the same file. This worked like a charm. Thanks! – Jason Baker Oct 09 '08 at 03:43
  • 12
    actually not just POD, it has to be an int type as well (int, short, bool, char...) – Matt Curtis Oct 09 '08 at 04:56
  • 9
    Note that this isn't just a question of how the value is initialized: const integral types defined like this may be turned into compile time constants by the implementation. This isn't always what you want, since it ups the binary dependency: client code needs recompilation if the value changes. – Steve Jessop Oct 09 '08 at 11:19
  • 1
    Although since this one's private, I guess that's not a concern here. Sorry. – Steve Jessop Oct 09 '08 at 11:24
  • it must be integral and always a constant expression (never a function) – Ramadheer Singh May 20 '10 at 22:48
  • 6
    @Martin: in addition to the correction s/POD/integral type/, if the address is ever taken then there needs to be a definition also. Strange as it may sound, the declaration with initializer, in the class definition, is not a definition. The *templated const idiom* provides a workaround for the cases where you need the definition in a header file. Another and simpler workaround is a function that produces the value of a local static constant. Cheers & hth., – Cheers and hth. - Alf Oct 15 '10 at 18:13
  • 1
    Cant the initalization be put in the header if your using header watchers causing the header just to be included once? – Sebastian Hoffmann Jan 07 '12 at 14:44
  • @Paranaix: 1) You mean `Header Guards`. 2) As noted by Matt Curtis: Only the special case of `const` int/char/bool (see last paragraph above) – Martin York Jan 07 '12 at 20:42
  • 4
    You might add a clarification that int foo::i =0; should not be inside a function (including the main function). I had it at the beginning of my main function and it doesn't like that. – qwerty9967 Apr 15 '13 at 19:33
  • 2
    @MattCurtis "or any type if you're using C++11". Although worth adding only I understand if additionally specified as constexpr for non-integral types. – wardw Apr 27 '13 at 17:23
  • @wards, can you use `constexpr` with non-integral types? – sasha.sochka Jul 30 '13 at 22:18
  • 1
    @sasha.sochka It can return any http://en.cppreference.com/w/cpp/concept/LiteralType – Rag Feb 10 '14 at 21:01
  • @sasha.sochka not with types that have non-default destructors. – Utkarsh Bhardwaj Jun 03 '15 at 07:34
  • I've been misquoted in this answer, its content belongs to its editors not me. I certainly didn't say "any const type", or "any type in C++11". – Matt Curtis Jul 18 '15 at 10:30
  • 1
    @LokiAstari It's ok - thanks for the edit. I just noticed in some answers on SO sometimes it's confusing who's saying what. (Also sometimes my answers have been edited in ways I think changes the meaning. That's the price of gamification I guess!) – Matt Curtis Jul 22 '15 at 11:50
  • Actually in the CPP file **defining** is enough (instead of also initializing, which is optional): `int foo::i;` – Melroy van den Berg Sep 17 '18 at 16:32
  • You mentioned it can be in the source if not shared. Would there be a pro/con to do it if the value is "Private Static" since that cannot be shared and it makes it easier to write in my opinion but I don't know if theirs a negative to doing it like that other then for future use if you plan to use it you can't simply set it to public you'd have to declare it in the header then. – Jeremy Trifilo Dec 31 '18 at 22:37
  • What if it is not an elemental datatype? – Dustin K Feb 19 '20 at 14:26
  • @DustinK The first technique shown above works for all types. The second technique is an optimization for integer types. – Martin York Feb 19 '20 at 19:19
  • @Martin York "C++ allows the simplification of the above if the static member variable is of const int type (e.g. int, bool, char).", which standard begins, c++98, or c++03? – John Aug 17 '21 at 05:22
  • @John Probably C++03. C++98 had very few optimizations or shortcuts built into the language (it was basically your direct language definition it did not even have a standard STL back in those days), these only came after lots of use and people pointing out that we could optimize this with a simple change to the language requirements. – Martin York Aug 17 '21 at 15:59
  • @MartinYork What if the class is a generic class ? I mean defined as `template class MyClass` – Bemipefe Nov 21 '22 at 14:30
  • I found this useful for generic class / template: https://stackoverflow.com/questions/3229883/static-member-initialization-in-a-class-template/3229904#comment131546544_3229904 – Bemipefe Nov 25 '22 at 14:24
112

For a variable:

foo.h:

class foo
{
private:
    static int i;
};

foo.cpp:

int foo::i = 0;

This is because there can only be one instance of foo::i in your program. It's sort of the equivalent of extern int i in a header file and int i in a source file.

For a constant you can put the value straight in the class declaration:

class foo
{
private:
    static int i;
    const static int a = 42;
};
Matt Curtis
  • 23,168
  • 8
  • 60
  • 63
  • 3
    This is a valid point. I will add this too my explanation. But it should be noted this only works for POD types. – Martin York Oct 09 '08 at 03:44
  • Since when, C++ allows to be just good with declaration in-class and no definition for integral types. Since C++98 itself or C++03 or when ? Please share authentic links please. C++ standard wording is not in sync with the compilers. They mention the member shall still be defined if they are used. So, I don't need the C++ Standard quoting though – smRaj Sep 20 '14 at 15:42
  • 3
    I wonder why `private` variables can be initialized outside Class here, can this be done for non-static variables also. – Krishna Oza Jul 10 '15 at 11:19
  • Have you found the explanation? @Krishna_Oza – nn0p Sep 14 '16 at 09:16
  • @nn0p not yet , but non-static private variables initialization outside `Class` doesn't makes any sense in Cpp. – Krishna Oza Sep 14 '16 at 10:20
  • There is a problem with initializing the static const variable in the class definition. If you put this class definition in a .h or .hpp file and include it in multiple .cpp files, you may get "unused variable" warnings during compilation. Better to initialize static variables in the classes .cpp file. – bearvarine Sep 27 '17 at 13:14
  • How can a private static variable belonging to one class be used by other source files that include its header? Isn't static meant to be visible only inside the source file of that class? – Abdel Aleem Aug 22 '21 at 11:44
  • @AbdelAleem static means lots of different stuff because C and C++ tend to to overload existing keywords rather than reserve new ones that might cause existing code to break. It's used here because of C++'s foundation on C and an old linker model, which is what the OP is trying to use. There's more ways to do it. – Matt Curtis Aug 24 '21 at 23:29
98

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;
};
Xunie
  • 437
  • 4
  • 21
Die in Sente
  • 9,546
  • 3
  • 35
  • 41
  • 3
    This is possible since C++17, which is in currently in progress of becoming the new standard. – Grebu Jul 21 '17 at 20:38
35

For future viewers of this question, I want to point out that you should avoid what monkey0506 is suggesting.

Header files are for declarations.

Header files get compiled once for every .cpp file that directly or indirectly #includes them, and code outside of any function is run at program initialization, before main().

By putting: foo::i = VALUE; into the header, foo:i will be assigned the value VALUE (whatever that is) for every .cpp file, and these assignments will happen in an indeterminate order (determined by the linker) before main() is run.

What if we #define VALUE to be a different number in one of our .cpp files? It will compile fine and we will have no way of knowing which one wins until we run the program.

Never put executed code into a header for the same reason that you never #include a .cpp file.

Include guards (which I agree you should always use) protect you from something different: the same header being indirectly #included multiple times while compiling a single .cpp file.

sifferman
  • 2,955
  • 2
  • 27
  • 37
Joshua Clayton
  • 1,669
  • 18
  • 29
  • 4
    You're right about this of course, except in the case of a class template (which isn't asked about, but I happen to be dealing with a lot). So if the class is fully defined and not a class template, then put these static members in a separate CPP file, but for class templates the definition has to be in the same translation unit (e.g., the header file). – monkey0506 Jan 18 '13 at 20:22
  • @monkey_05_06: That just seems to be an argument to avoid static member in templated code: You already end up with one static member for each instantiation of the class. the problem is worsened by possibly compiling the header into multiple cpp files... You could get a raft of conflicting definitions. – Joshua Clayton Feb 26 '13 at 05:13
  • http://publib.boulder.ibm.com/infocenter/macxhelp/v6v81/index.jsp?topic=%2Fcom.ibm.vacpp6m.doc%2Flanguage%2Fref%2Fclrc16static_data_members_and_templ.htm This link depicts instantiating static template members int the main function, which is cleaner, if a bit of a burden. – Joshua Clayton Feb 26 '13 at 05:29
  • 2
    Your argument is really huge stretch. First you cannot #define VALUE because macros name has ot be a valid identifier. And Even if you could - who would do that? Header files are for declaration - ? C'mon.. The only cases where you should avoid putting values in the header is to fight odr-used. And putting the value in the header may lead to unnecessary recompilation whenever you need to change the value. – Aleksander Fular Mar 04 '16 at 15:39
23

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.

Johann Gerell
  • 24,991
  • 10
  • 72
  • 122
19
int foo::i = 0; 

Is the correct syntax for initializing the variable, but it must go in the source file (.cpp) rather than in the header.

Because it is a static variable the compiler needs to create only one copy of it. You have to have a line "int foo:i" some where in your code to tell the compiler where to put it otherwise you get a link error. If that is in a header you will get a copy in every file that includes the header, so get multiply defined symbol errors from the linker.

David Dibben
  • 18,460
  • 6
  • 41
  • 41
16

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?

This awesome C++17 feature allow us to:

  • conveniently use just a single memory address for each constant
  • store it as a constexpr: How to declare constexpr extern?
  • do it in a single line from one header

main.cpp

#include <cassert>

#include "notmain.hpp"

int main() {
    // Both files see the same memory address.
    assert(&notmain_i == notmain_func());
    assert(notmain_i == 42);
}

notmain.hpp

#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP

inline constexpr int notmain_i = 42;

const int* notmain_func();

#endif

notmain.cpp

#include "notmain.hpp"

const int* notmain_func() {
    return &notmain_i;
}

Compile and run:

g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main

GitHub upstream.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985
15

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.

Ziezi
  • 6,375
  • 3
  • 39
  • 49
Kris Kwiatkowski
  • 350
  • 3
  • 10
11

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.

monkey0506
  • 2,489
  • 1
  • 21
  • 27
  • 26
    #include guards just prevent multiple definitions per translation unit. – Paul Fultz II Apr 20 '12 at 15:43
  • 3
    regarding good style:you should add comment on the closing endif: `#endif // FOO_H` – Riga Jul 04 '12 at 13:08
  • 13
    This only works if you have only one compile unit that includes foo.h. If two or more cpps include foo.h, which is a typical situation, each cpp would declare the same static variable so the linker would complain with multiple definition of `foo::i' unless you use a package compilation with the files (compile only one file that include all cpps). But although package compilation is great the solution to the problem is to declare (int foo::i = 0;) in a cpp! – Alejadro Xalabarder Dec 31 '13 at 02:51
  • 1
    Or just use `#pragma once` – tambre Oct 25 '16 at 13:36
  • `#pragma once` is a solution for multiple definitions through translation units, but it should be the final, last resort, solution, not one's coding style... – Marine Galantin Feb 12 '22 at 17:12
7

The linker problem you encountered is probably caused by:

  • Providing both class and static member definition in header file,
  • Including this header in two or more source files.

This is a common problem for those who starts with C++. Static class member must be initialized in single translation unit i.e. in single source file.

Unfortunately, the static class member must be initialized outside of the class body. This complicates writing header-only code, and, therefore, I am using quite different approach. You can provide your static object through static or non-static class function for example:

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

    void func() {
        int &object = getValueInstance();
        object += 5;
    }
};
no one special
  • 1,608
  • 13
  • 32
  • 1
    I'm still a complete n00b as far as C++ goes, but this looks brilliant to me, thank you so much! I get perfect life-cycle management of the singleton object for free. – Rafael Kitover Nov 06 '19 at 15:18
6

You can also include the assignment in the header file if you use header guards. I have used this technique for a C++ library I have created. Another way to achieve the same result is to use static methods. For example...

class Foo
   {
   public:
     int GetMyStatic() const
     {
       return *MyStatic();
     }

   private:
     static int* MyStatic()
     {
       static int mStatic = 0;
       return &mStatic;
     }
   }

The above code has the "bonus" of not requiring a CPP/source file. Again, a method I use for my C++ libraries.

4

I follow the idea from Karl. I like it and now I use it as well. I've changed a little bit the notation and add some functionality

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

this outputs

mystatic value 7
mystatic value 3
is my static 1 0
Alejadro Xalabarder
  • 1,551
  • 19
  • 14
3

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
andrew
  • 3,083
  • 4
  • 24
  • 29
3

What about a set_default() method?

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

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

We would only have to use the set_default(int x) method and our static variable would be initialized.

This would not be in disagreement with the rest of the comments, actually it follows the same principle of initializing the variable in a global scope, but by using this method we make it explicit (and easy to see-understand) instead of having the definition of the variable hanging there.

Ziezi
  • 6,375
  • 3
  • 39
  • 49
2

One "old-school" way to define constants is to replace them by a enum:

class foo
{
    private:
        enum {i = 0}; // default type = int
        enum: int64_t {HUGE = 1000000000000}; // may specify another type
};

This way doesn't require providing a definition, and avoids making the constant lvalue, which can save you some headaches, e.g. when you accidentally ODR-use it.

anatolyg
  • 26,506
  • 9
  • 60
  • 134
2

Here are all possibilities and errors in one simple example ...

#ifndef Foo_h
#define Foo_h

class Foo
{
  static const int a = 42; // OK
  static const int b {7};  // OK
  //static int x = 42; // ISO C++ forbids in-class initialization of non-const static member 'Foo::x'
  //static int y {7};  // ISO C++ forbids in-class initialization of non-const static member 'Foo::x'
  static int x;
  static int y;
  int m = 42;
  int n {7};
};

// Foo::x = 42;  // error: 'int Foo::x' is private
int Foo::x = 42; // OK in Foo.h if included in only one  *.cpp -> *.o file!
int Foo::y {7};  // OK

// int Foo::y {7};  // error: redefinition of 'int Foo::y'
   // ONLY if the compiler can see both declarations at the same time it, 
   // OTHERWISE you get a linker error

#endif // Foo_h

But better place this in Foo.cpp. This way you can separately compile each file and link them later, otherwise Foo:x will be present in multiple object files and cause a linker error. ...

// Foo::x = 42;  // error: 'int Foo::x' is private, bad if Foo::X is public!
int Foo::x = 42; // OK in Foo.h if included in only one  *.cpp -> *.o file!
int Foo::y {7};  // OK
cat
  • 2,871
  • 1
  • 23
  • 28
1

Does this serves your purpose?

//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;
}
corporateAbaper
  • 428
  • 3
  • 15
1

I just wanted to mention something a little strange to me when I first encountered this.

I needed to initialize a private static data member in a template class.

in the .h or .hpp, it looks something like this to initialize a static data member of a template class:

template<typename T>
Type ClassName<T>::dataMemberName = initialValue;
Tyler Heers
  • 134
  • 4