C++でJavaの静的初期化ブロックをシミュレートする【翻訳】
5162 ワード
静的初期化ブロックとは?
Javaには、静的初期化ブロックと呼ばれる構造がある.静的初期化ブロックは、Javaの最初の実行時にロードされます.たとえば、次のコードクリップを考慮します.
これにより、次のような出力が得られます.
この構造は様々な場合に有用である.Javaでは、クラスの静的メンバーのマルチロー初期化を許可する例が期待されます.また、スクリプトバインドなどのログ・レコードや任意の種類の登録コードやサブスクリプション・コードにも使用できます.
Javaの静的初期化ブロックの詳細については、この記事を参照してください.http://www.jianshu.com/p/e10871b7cbd4
C++はこのような構造方法に欠けているが,巧みに設計することで,そのいくつかの態様の特性を模倣することができる.
シミュレーションできるものは何ですか?
まず,C++でライブラリを実行するようなものはなく,少なくともJavaの意味でのライブラリではない.これは、上記の定義がC++で完全にコピーできないことを意味します.そのため、ターゲットは次の構造です.最小限のテンプレート を使用わかりやすい(つまり文法は簡単) は静的関数としてクラスの範囲内で を実行する.は決定点でコードを実行し、mainの開始 であることが望ましい.
構文
上記の要件(およびいくつかの制限)から、静的初期化ブロックの予想構文を以下に示す.
In foo.h:
In foo.cc:
In main.cc:
このコードは,上記のJavaコードフラグメントと同じ出力を生成することを期待する.
上記の考えを実現する.
ではstatic_に入りますinit.hは?主なコードから,実装の一部が何らかのレジストリであることが推測される.私たちは間違っていません.それはこのように見えます.
static_Initはvoid関数を管理および実行する単一のクラスです.init_func_typeは、パラメータを持たない関数を指す関数ポインタのtypedefです.静的メンバー関数を指すために使用されます.std::functionはここでも作業できますが、効率は低いです.実行メンバー関数は静的に設計されており,呼び出しの面で便利であるため,他の意図はない.
add_init_funcはどこで呼び出されますか?コツは、静的メンバーのコンストラクション関数で呼び出すことです.このコンストラクション関数はinit関数をパラメータとしてadd_に渡すinit_func. 理論的には、そこで関数を呼び出すことができます(「init関数レジストリ」は必要ありません).しかし、これにより、私たちのコードは「静的初期化順序の失敗」の影響を受けます.私たちはライブラリのお客様に制限を加えたくないので、この方法を採用しています.
登録コードにこっそり導入された静的メンバーには、アシスタントクラスを定義する必要があります.これは非常に簡単です.
この点では、私たちに必要なすべての機能があります.Foo.hには次のようなコードがあります.
foo.ccで:
正常に動作しますが、少しもきれいで優雅ではありません.
もっときれいにして
上記のコードを意図的に手配することで、マクロがどれだけ役に立つかを簡単に見ることができます.宣言セクションは非常に簡単です.
最後にセミコロンが欠けていることに注意してください.これは作者の個人的な好みにすぎず、私たちは自分の習慣に基づいて追加することができます.
同様に、実装部分:
ただし、ここでは、マクロが書き込むメンバー関数の署名で終了するため、最後にセミコロンを追加することはありません.これが、マクロが関数定義の一部として機能することを許可する理由です.
欠点
静的初期化関数は、「静的初期化順序の失敗」の影響を直接受けない(すなわち、任意のクラスの静的メンバーが完全に構築されることを期待できる)が、定義されていない順序と呼ばれるため、相互に依存しない可能性があるという問題がある.
このソリューションはC++の分野で少し見慣れない概念を導入した.これは、プログラマがコードを読むとオーバーヘッドが増加することを意味します.しかし、正しいコードで命名すると、私たちの意図は簡単に推測できるはずです.
また、クラスにデータ・メンバーを追加します.このデータ・メンバーは0サイズですが、正しくリンクするにはソース・ファイルに存在する必要があります.これは静的init関数がinlineであるはずがないことを意味する.
ソースコード
本明細書のソースコード(およびいくつかのサンプルコード)は、Github repositoryで参照できます.
本文は文章から訳す:
http://szelei.me/cpp-static-init-block/
原文の作者に感謝します
Javaには、静的初期化ブロックと呼ばれる構造がある.静的初期化ブロックは、Javaの最初の実行時にロードされます.たとえば、次のコードクリップを考慮します.
class Foo {
static {
// initialization code goes here
// called only once, when the class is loaded by the runtime
System.out.println("I'm the static initialization block of Foo
");
}
public Foo() {
System.out.println("I'm the constructor of Foo
");
}
public static void Main(String[] args) {
Foo foo1 = new Foo();
Foo foo2 = new Foo();
}
}
これにより、次のような出力が得られます.
I'm the static initialization block of Foo
I'm the constructor of Foo
I'm the constructor of Foo
この構造は様々な場合に有用である.Javaでは、クラスの静的メンバーのマルチロー初期化を許可する例が期待されます.また、スクリプトバインドなどのログ・レコードや任意の種類の登録コードやサブスクリプション・コードにも使用できます.
Javaの静的初期化ブロックの詳細については、この記事を参照してください.http://www.jianshu.com/p/e10871b7cbd4
C++はこのような構造方法に欠けているが,巧みに設計することで,そのいくつかの態様の特性を模倣することができる.
シミュレーションできるものは何ですか?
まず,C++でライブラリを実行するようなものはなく,少なくともJavaの意味でのライブラリではない.これは、上記の定義がC++で完全にコピーできないことを意味します.そのため、ターゲットは次の構造です.
構文
上記の要件(およびいくつかの制限)から、静的初期化ブロックの予想構文を以下に示す.
In foo.h:
#pragma once
#include "static_init.h"
class Foo
{
public:
Foo();
DECLARE_STATIC_INIT(Foo);
};
In foo.cc:
#include
#include "foo.h"
Foo::Foo()
{
std::cout << "I'm the constructor of Foon";
}
STATIC_INIT(Foo)
{
std::cout << "I'm the static initialization block of Foon";
}
In main.cc:
#include
#include "static_init.h"
#include "foo.h"
int main()
{
static_init::execute();
Foo foo1, foo2;
}
このコードは,上記のJavaコードフラグメントと同じ出力を生成することを期待する.
上記の考えを実現する.
ではstatic_に入りますinit.hは?主なコードから,実装の一部が何らかのレジストリであることが推測される.私たちは間違っていません.それはこのように見えます.
typedef void (*init_func_type)();
class static_init
{
public:
static static_init& instance()
{
static static_init inst;
return inst;
}
void add_init_func(init_func_type f) { funcs_.push_back(f); }
static void execute()
{
auto& inst = instance();
for (auto& c : inst.funcs_) c();
}
private:
static_init() {}
std::vector funcs_;
};
static_Initはvoid関数を管理および実行する単一のクラスです.init_func_typeは、パラメータを持たない関数を指す関数ポインタのtypedefです.静的メンバー関数を指すために使用されます.std::functionはここでも作業できますが、効率は低いです.実行メンバー関数は静的に設計されており,呼び出しの面で便利であるため,他の意図はない.
add_init_funcはどこで呼び出されますか?コツは、静的メンバーのコンストラクション関数で呼び出すことです.このコンストラクション関数はinit関数をパラメータとしてadd_に渡すinit_func. 理論的には、そこで関数を呼び出すことができます(「init関数レジストリ」は必要ありません).しかし、これにより、私たちのコードは「静的初期化順序の失敗」の影響を受けます.私たちはライブラリのお客様に制限を加えたくないので、この方法を採用しています.
登録コードにこっそり導入された静的メンバーには、アシスタントクラスを定義する必要があります.これは非常に簡単です.
class static_init_helper
{
public:
static_init_helper(init_func_type f)
{
static_init::instance().add_init_func(f);
}
};
この点では、私たちに必要なすべての機能があります.Foo.hには次のようなコードがあります.
#pragma once
#include "static_init.h"
class Foo
{
public:
Foo();
static void static_init_func();
static static_init_helper Foo_static_init_helper;
};
foo.ccで:
#include
#include "foo.h"
Foo::Foo()
{
std::cout << "I'm the constructor of Foon";
}
// This is where the registration code (i.e. the constructor of the helper class) gets called:
static_init_helper Foo::Foo_static_init_helper(&Foo::static_init_func);
// And this is the implementation of the static init function,
// an actual static member function of the class.
void Foo::static_init_func()
{
std::cout << "I'm the static initialization block of Foon";
}
正常に動作しますが、少しもきれいで優雅ではありません.
もっときれいにして
上記のコードを意図的に手配することで、マクロがどれだけ役に立つかを簡単に見ることができます.宣言セクションは非常に簡単です.
#define DECLARE_STATIC_INIT(ClassName)
static void static_init_func();
static static_init_helper ClassName##_static_init_helper
最後にセミコロンが欠けていることに注意してください.これは作者の個人的な好みにすぎず、私たちは自分の習慣に基づいて追加することができます.
同様に、実装部分:
#define STATIC_INIT(ClassName)
static_init_helper ClassName::ClassName##_static_init_helper(&ClassName::static_init_func);
void ClassName::static_init_func()
ただし、ここでは、マクロが書き込むメンバー関数の署名で終了するため、最後にセミコロンを追加することはありません.これが、マクロが関数定義の一部として機能することを許可する理由です.
欠点
静的初期化関数は、「静的初期化順序の失敗」の影響を直接受けない(すなわち、任意のクラスの静的メンバーが完全に構築されることを期待できる)が、定義されていない順序と呼ばれるため、相互に依存しない可能性があるという問題がある.
このソリューションはC++の分野で少し見慣れない概念を導入した.これは、プログラマがコードを読むとオーバーヘッドが増加することを意味します.しかし、正しいコードで命名すると、私たちの意図は簡単に推測できるはずです.
また、クラスにデータ・メンバーを追加します.このデータ・メンバーは0サイズですが、正しくリンクするにはソース・ファイルに存在する必要があります.これは静的init関数がinlineであるはずがないことを意味する.
ソースコード
本明細書のソースコード(およびいくつかのサンプルコード)は、Github repositoryで参照できます.
本文は文章から訳す:
http://szelei.me/cpp-static-init-block/
原文の作者に感謝します