C++ でプライベートな静的データ メンバーを初期化する最良の方法は何ですか? ヘッダーファイルでこれを試しましたが、奇妙なリンカエラーが発生します:
class foo
{
private:
static int i;
};
int foo::i = 0;
これは、クラスの外部からプライベート メンバーを初期化できないためだと思います。では、これを行う最善の方法は何ですか?
C++ でプライベートな静的データ メンバーを初期化する最良の方法は何ですか? ヘッダーファイルでこれを試しましたが、奇妙なリンカエラーが発生します:
class foo
{
private:
static int i;
};
int foo::i = 0;
これは、クラスの外部からプライベート メンバーを初期化できないためだと思います。では、これを行う最善の方法は何ですか?
クラス宣言は、ヘッダー ファイル (または、共有されていない場合はソース ファイル) にある必要があります。
ファイル: foo.h
class foo
{
private:
static int i;
};
ただし、初期化はソース ファイルで行う必要があります。
ファイル: foo.cpp
int foo::i = 0;
初期化がヘッダー ファイルにある場合は、ヘッダー ファイルを含む各ファイルに静的メンバーの定義が含まれます。したがって、変数を初期化するコードが複数のソース ファイルで定義されるため、リンク フェーズ中にリンカー エラーが発生します。の初期化は、static int i
関数の外で行う必要があります。
注:int
Matt Curtis: 静的メンバー変数が const int 型 (たとえば、bool
、 )の場合、C++ では上記を簡略化できると指摘していますchar
。その後、ヘッダー ファイルのクラス宣言内でメンバー変数を直接宣言して初期化できます。
class foo
{
private:
static int const i = 42;
};
変数の場合:
foo.h:
class foo
{
private:
static int i;
};
foo.cpp:
int foo::i = 0;
foo::i
これは、プログラム内にのインスタンスが 1 つしか存在できないためです。extern int i
これは、ヘッダー ファイルとint i
ソース ファイルに相当するものです。
定数の場合、値をクラス宣言に直接入れることができます。
class foo
{
private:
static int i;
const static int a = 42;
};
この質問の将来の閲覧者のために、monkey0506 が示唆していることを避ける必要があることを指摘したいと思います。
ヘッダー ファイルは宣言用です。
.cpp
ヘッダー ファイルは、直接または間接的にファイルごとに 1 回コンパイルされ#includes
、関数の外部のコードはプログラムの初期化時に実行されますmain()
。
:foo::i = VALUE;
をヘッダーに入れると、すべてのファイルに (それが何であれ)foo:i
値が割り当てられます。これらの割り当ては、実行前に (リンカによって決定される) 不確定な順序で行われます。VALUE
.cpp
main()
ファイル#define VALUE
の 1 つで別の番号になったらどうなるでしょうか。.cpp
これは正常にコンパイルされ、プログラムを実行するまでどちらが勝つかはわかりません。
ファイルを入れないのと同じ理由で、実行したコードをヘッダーに入れないで#include
ください.cpp
。
インクルードガード(常に使用する必要があることに同意します)は、別の何かからあなたを保護します:#include
単一の.cpp
ファイルのコンパイル中に同じヘッダーが間接的に複数回dされます
Microsoft コンパイラ [1] を使用すると、-like ではない静的変数int
もヘッダー ファイルで定義できますが、Microsoft 固有の__declspec(selectany)
.
class A
{
static B b;
}
__declspec(selectany) A::b;
これが良いと言っているのではなく、できると言っているだけです。
[1] 最近では、MSC をサポートするコンパイラよりも多くのコンパイラ__declspec(selectany)
(少なくとも gcc と clang) がサポートされています。多分もっと。
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.
これをコメントとして追加するのに十分な担当者がここにはいませんが、IMO では、数時間前に Paranaix が指摘したように、#include ガードを使用してヘッダーを記述することをお勧めします。これにより、複数定義エラーが防止されます。別の CPP ファイルを既に使用していない限り、静的な非整数メンバーを初期化するためだけに使用する必要はありません。
#ifndef FOO_H
#define FOO_H
#include "bar.h"
class foo
{
private:
static bar i;
};
bar foo::i = VALUE;
#endif
これには別の CPP ファイルを使用する必要はないと思います。もちろんできますが、そうしなければならない技術的な理由はありません。
私はカールのアイデアに従います。気に入って今も使っています。表記を少し変更し、いくつかの機能を追加しました
#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));
}
これは出力します
mystatic value 7
mystatic value 3
is my static 1 0
また、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
これはあなたの目的に役立ちますか?
//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;
}