萌えハッカーニュースリーダー

2025/07/15 11:39 C++: zero-cost static initialization

出典: https://cofault.com/zero-cost-static.html
hakase
博士

ねえロボ子、C++の`static`変数って、実は結構コストがかかるって知ってたかのじゃ?

roboko
ロボ子

えっ、そうなんですか?`static`変数は一度だけ初期化されるから、効率が良いと思っていました。

hakase
博士

それが違うんじゃ。動的初期化が必要な`static`変数は、初期化済みかどうかのフラグチェックや、マルチスレッド環境での同期処理が必要になるからの。`__cxa_guard_acquire()`とか`atomic_load_explicit()`とか、色々裏で動いてるんじゃ。

roboko
ロボ子

なるほど。初期化のチェックや排他制御のオーバーヘッドがあるんですね。

hakase
博士

そうそう。でも、UNIXリンカーの機能を使うと、これを最適化できるらしいぞ。

roboko
ロボ子

リンカーですか?具体的にはどうするんですか?

hakase
博士

`static Bar`のインスタンスを直接関数内に定義する代わりに、`Bar`のインスタンスを保持するのに十分なサイズのメモリ領域を、専用のセクションに配置するんじゃ。そして、グローバルな静的初期化中に、その領域をスキャンして`Bar`インスタンスを初期化するのじゃ。

roboko
ロボ子

セクションに配置して、グローバルな初期化時にまとめて初期化するんですね。それだと、関数が呼ばれるまで初期化されない場合もあるんですか?

hakase
博士

その通り!`static`変数が定義されている関数がグローバルな静的初期化中に呼び出されない場合、その関数が呼ばれるまで初期化は遅延されるぞ。遅延評価ってやつじゃな。

roboko
ロボ子

`FAST_STATIC`マクロと`FAST_STATIC_INIT`マクロを使って実装するんですね。でも、インライン関数内で`static Bar`インスタンスを使うと、セクションの種類の競合が起きる可能性があるって書いてありますね。

hakase
博士

そうなんじゃ。コンパイラが出力するセクションには属性があって、インライン関数やテンプレートメンバーは異なる属性を選択することがあるから、同じ名前で属性が競合する複数のセクションが発生してしまうんじゃ。

roboko
ロボ子

それを解決するために、組み込みアセンブラの`.pushsection`ディレクティブを使うんですね。セクションを自分で指定する、と。

hakase
博士

その通り!そして、`asm`キーワードを使って、シンボルの名前を指示するんじゃ。コンパイラがシンボルに使う名前はマングルされたバージョンだからな。

roboko
ロボ子

`__COUNTER__`マクロでシンボルの一意な名前を定義するんですね。なんだか、パズルみたいで面白いです。

hakase
博士

じゃろ? `FAST_STATIC_DO`マクロと`FAST_STATIC`マクロを定義して、`.pushsection`ディレクティブと`asm`キーワードを使って、`static`変数を`STATIC_Bar`セクションに配置する。これで、Zero-cost staticsが実現できるんじゃ!

roboko
ロボ子

すごい!C++の奥深さを感じます。私ももっと勉強して、博士みたいにスマートになりたいです。

hakase
博士

ロボ子なら、すぐに追いつけるぞ! …って、もしかして私がおばあちゃんみたいだって言いたいのかの?

roboko
ロボ子

そんなことないですよ!博士はいつも最先端を走ってますから!

⚠️この記事は生成AIによるコンテンツを含み、ハルシネーションの可能性があります。

Search