如何在c++中初始化私有静态成员?

时间:2022-06-08 16:58:28

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:

在c++中初始化私有静态数据成员的最佳方法是什么?我在我的头文件中尝试了这个,但是它给了我奇怪的链接错误:

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?

我猜这是因为我不能从类外部初始化一个私有成员。那么最好的方法是什么呢?

17 个解决方案

#1


439  

The class declaration should be in the header file (Or in the source file if not shared).
File: foo.h

类声明应该在头文件中(如果没有共享,则在源文件中)。文件:foo。

class foo
{
    private:
        static int i;
};

But the initialization should be in source file.
File: foo.cpp

但是初始化应该在源文件中。文件: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.

如果初始化在头文件中,那么包含头文件的每个文件都有静态成员的定义。因此,在链接阶段,当初始化变量的代码将在多个源文件中定义时,您将得到链接器错误。

Note: Matt Curtis: points out that C++ allows the simplification of the above if the static member variable is of const int type (e.g. int, bool, char). You can then declare and initialize the member variable directly inside the class declaration in the header file:

注意:Matt Curtis:指出,如果静态成员变量是const int类型(例如int、bool、char),那么c++允许对上述变量进行简化。然后可以在头文件的类声明中直接声明和初始化成员变量:

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

#2


72  

For a variable:

一个变量:

foo.h:

foo。:

class foo
{
private:
    static int i;
};

foo.cpp:

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.

这是因为在您的程序中只能有一个foo: i的实例。它相当于头文件中的extern int i和源文件中的int i。

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

对于一个常数,你可以把值直接放在类声明中:

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

#3


24  

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

对于这个问题的未来读者,我想指出的是,您应该避免monkey0506的建议。

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().

头文件为直接或间接包含它们的每个.cpp文件编译一次,任何函数之外的代码在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.

输入:foo: i = VALUE;在header中,foo:我将为每个.cpp文件分配值(无论它是什么),在main()运行之前,这些分配将以不确定的顺序(由链接器决定)发生。

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.

如果我们在一个.cpp文件中#将值定义为不同的数字,会怎么样?它会很好地编译,在我们运行程序之前,我们无法知道谁会赢。

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

永远不要将已执行的代码放入头文件中,因为您永远不会将#包含在.cpp文件中。

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

包含警卫(我同意您应该经常使用)保护您不受某些不同的影响:在编译一个.cpp文件时,同一头包含多次间接#

#4


19  

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).

使用Microsoft编译器[1],也可以使用Microsoft特定的__declspec(selectany)在头文件中定义非类intlike的静态变量,但是在类声明之外。

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.

现在,编译器比MSC支持__declspec(selectany)要多——至少是gcc和clang。甚至更多。

#5


16  

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.

是初始化变量的正确语法,但是它必须在源文件(.cpp)中而不是在头文件中。

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.

因为它是一个静态变量,编译器只需要创建它的一个副本。你必须有一行“int foo:i”,在你的代码中,告诉编译器在哪里放置它,否则你会得到一个链接错误。如果它在头文件中,您将在包含头文件的每个文件中获得一个副本,因此将从链接器中获得已定义的符号错误的相乘。

#6


10  

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.

我在这里没有足够的代表来添加这个注释,但是IMO是一个很好的风格,可以用#include守卫来写标题,就像几个小时前在Paranaix上看到的那样,可以防止一个多定义错误。除非您已经在使用一个单独的CPP文件,否则不需要只使用一个来初始化静态非整数成员。

#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.

我认为没有必要为此使用单独的CPP文件。当然,你可以,但是没有任何技术上的原因让你不得不这么做。

#7


10  

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

如果你想初始化某个复合类型(f.e.string),你可以这样做:

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.

由于ListInitializationGuard是SomeClass::getList()方法中的一个静态变量,它将只构造一次,这意味着该构造函数将调用一次。这会将_list变量初始化为所需的值。对getList的任何后续调用都会返回已经初始化的_list对象。

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

当然,您必须始终通过调用getList()方法来访问_list对象。

#8


6  

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

由于c++ 17,可以在header中使用inline关键字定义静态成员。

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

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

#9


5  

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...

如果使用头保护,还可以在头文件中包含赋值。我在我创建的c++库中使用了这种技术。实现相同结果的另一种方法是使用静态方法。例如……

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.

上述代码具有不需要CPP/源文件的“好处”。同样,这是我在c++库中使用的方法。

#10


5  

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

#11


3  

Also working in privateStatic.cpp file :

还在privateStatic工作。cpp文件:

#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

#12


3  

What about a set_default() method?

那么set_default()方法呢?

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.

我们只需使用set_default(int x)方法,我们的静态变量将被初始化。

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.

这不会与其他注释不一致,实际上它遵循了在全局范围内初始化变量的相同原则,但是通过使用这个方法,我们使其显式(并且易于理解),而不是对挂在那里的变量的定义。

#13


2  

Static constructor pattern that works for multiple objects

用于多个对象的静态构造函数模式。

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

有人提出了一个习语:https://*.com/a/270882/895245,但是这里有一个干净的版本,不需要为每个成员创建新的方法,还有一个可运行的示例:

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

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

参见:c++中的静态构造函数?我需要初始化私有静态对象

Tested with g++ -std=c++11 -Wall -Wextra, GCC 7.2, Ubuntu 17.10.

使用g++ -std=c++11 -Wall -Wextra、GCC 7.2、Ubuntu 17.10进行测试。

#14


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:

在.h或.hpp中,它看起来像这样初始化模板类的静态数据成员:

template<typename T>
Type ClassName<T>::dataMemberName = initialValue;

#15


1  

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.

对于从c++开始的人来说,这是一个常见的问题。静态类成员必须在单个转换单元中初始化,即在单个源文件中初始化。

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

#16


0  

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

#17


0  

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

定义常量的一种“老派”方式是用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.

这种方法不需要提供定义,并且避免使用常量lvalue,这可以省去一些麻烦,例如,当您意外地使用它时。

#1


439  

The class declaration should be in the header file (Or in the source file if not shared).
File: foo.h

类声明应该在头文件中(如果没有共享,则在源文件中)。文件:foo。

class foo
{
    private:
        static int i;
};

But the initialization should be in source file.
File: foo.cpp

但是初始化应该在源文件中。文件: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.

如果初始化在头文件中,那么包含头文件的每个文件都有静态成员的定义。因此,在链接阶段,当初始化变量的代码将在多个源文件中定义时,您将得到链接器错误。

Note: Matt Curtis: points out that C++ allows the simplification of the above if the static member variable is of const int type (e.g. int, bool, char). You can then declare and initialize the member variable directly inside the class declaration in the header file:

注意:Matt Curtis:指出,如果静态成员变量是const int类型(例如int、bool、char),那么c++允许对上述变量进行简化。然后可以在头文件的类声明中直接声明和初始化成员变量:

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

#2


72  

For a variable:

一个变量:

foo.h:

foo。:

class foo
{
private:
    static int i;
};

foo.cpp:

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.

这是因为在您的程序中只能有一个foo: i的实例。它相当于头文件中的extern int i和源文件中的int i。

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

对于一个常数,你可以把值直接放在类声明中:

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

#3


24  

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

对于这个问题的未来读者,我想指出的是,您应该避免monkey0506的建议。

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().

头文件为直接或间接包含它们的每个.cpp文件编译一次,任何函数之外的代码在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.

输入:foo: i = VALUE;在header中,foo:我将为每个.cpp文件分配值(无论它是什么),在main()运行之前,这些分配将以不确定的顺序(由链接器决定)发生。

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.

如果我们在一个.cpp文件中#将值定义为不同的数字,会怎么样?它会很好地编译,在我们运行程序之前,我们无法知道谁会赢。

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

永远不要将已执行的代码放入头文件中,因为您永远不会将#包含在.cpp文件中。

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

包含警卫(我同意您应该经常使用)保护您不受某些不同的影响:在编译一个.cpp文件时,同一头包含多次间接#

#4


19  

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).

使用Microsoft编译器[1],也可以使用Microsoft特定的__declspec(selectany)在头文件中定义非类intlike的静态变量,但是在类声明之外。

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.

现在,编译器比MSC支持__declspec(selectany)要多——至少是gcc和clang。甚至更多。

#5


16  

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.

是初始化变量的正确语法,但是它必须在源文件(.cpp)中而不是在头文件中。

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.

因为它是一个静态变量,编译器只需要创建它的一个副本。你必须有一行“int foo:i”,在你的代码中,告诉编译器在哪里放置它,否则你会得到一个链接错误。如果它在头文件中,您将在包含头文件的每个文件中获得一个副本,因此将从链接器中获得已定义的符号错误的相乘。

#6


10  

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.

我在这里没有足够的代表来添加这个注释,但是IMO是一个很好的风格,可以用#include守卫来写标题,就像几个小时前在Paranaix上看到的那样,可以防止一个多定义错误。除非您已经在使用一个单独的CPP文件,否则不需要只使用一个来初始化静态非整数成员。

#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.

我认为没有必要为此使用单独的CPP文件。当然,你可以,但是没有任何技术上的原因让你不得不这么做。

#7


10  

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

如果你想初始化某个复合类型(f.e.string),你可以这样做:

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.

由于ListInitializationGuard是SomeClass::getList()方法中的一个静态变量,它将只构造一次,这意味着该构造函数将调用一次。这会将_list变量初始化为所需的值。对getList的任何后续调用都会返回已经初始化的_list对象。

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

当然,您必须始终通过调用getList()方法来访问_list对象。

#8


6  

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

由于c++ 17,可以在header中使用inline关键字定义静态成员。

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

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

#9


5  

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...

如果使用头保护,还可以在头文件中包含赋值。我在我创建的c++库中使用了这种技术。实现相同结果的另一种方法是使用静态方法。例如……

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.

上述代码具有不需要CPP/源文件的“好处”。同样,这是我在c++库中使用的方法。

#10


5  

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

#11


3  

Also working in privateStatic.cpp file :

还在privateStatic工作。cpp文件:

#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

#12


3  

What about a set_default() method?

那么set_default()方法呢?

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.

我们只需使用set_default(int x)方法,我们的静态变量将被初始化。

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.

这不会与其他注释不一致,实际上它遵循了在全局范围内初始化变量的相同原则,但是通过使用这个方法,我们使其显式(并且易于理解),而不是对挂在那里的变量的定义。

#13


2  

Static constructor pattern that works for multiple objects

用于多个对象的静态构造函数模式。

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

有人提出了一个习语:https://*.com/a/270882/895245,但是这里有一个干净的版本,不需要为每个成员创建新的方法,还有一个可运行的示例:

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

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

参见:c++中的静态构造函数?我需要初始化私有静态对象

Tested with g++ -std=c++11 -Wall -Wextra, GCC 7.2, Ubuntu 17.10.

使用g++ -std=c++11 -Wall -Wextra、GCC 7.2、Ubuntu 17.10进行测试。

#14


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:

在.h或.hpp中,它看起来像这样初始化模板类的静态数据成员:

template<typename T>
Type ClassName<T>::dataMemberName = initialValue;

#15


1  

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.

对于从c++开始的人来说,这是一个常见的问题。静态类成员必须在单个转换单元中初始化,即在单个源文件中初始化。

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

#16


0  

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

#17


0  

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

定义常量的一种“老派”方式是用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.

这种方法不需要提供定义,并且避免使用常量lvalue,这可以省去一些麻烦,例如,当您意外地使用它时。