コード内の任意の場所に1回限りのブロック(C ++ 11以降)

プログラムが正確に1回実行する必要がある大きな(またはそうでない)コードを記述する必要がある人のために、小さな既製のソリューションを提示したいと思います。 さらに、(合理的なC ++構文規則の制限内で)どこにでも配置する必要がある場合があります。 この必要性がプロジェクト全体で数回より頻繁に発生する場合は、少なくとも多少は作業を行い、可能であればあまり松葉杖ではない解決策があるとよいでしょう。



まっすぐに



長い間考えずに、標準C ++ 11以降で動作するコードをすぐに投稿します。



#include <iostream> #define DO_ONCE(...) { static bool _do_once_ = ([&](){ __VA_ARGS__ }(), true); (void)_do_once_; } void Foo(int val) { using namespace std; //  _do_once_        DO_ONCE static unsigned int _do_once_ = 1; DO_ONCE ( cout << "[First call of 'Foo' function]" << endl; ) cout << "Calls: " << _do_once_++ << ", value: " << val << endl; } int main(int argc, char** argv) { using namespace std; for (auto val : {1, 2, 3}) { Foo(val); DO_ONCE ( Foo(val); ) } system("pause > nul"); return 0; } /*  : [First call of 'Foo' function] Calls: 1, value: 1 Calls: 2, value: 1 Calls: 3, value: 2 Calls: 4, value: 3 /*
      
      





必要なすべての作業を行う最も重要なコードを検討してください。



 #define DO_ONCE(...) { static bool _do_once_ = ([&](){__VA_ARGS__}(), true); (void)_do_once_; }
      
      





あまり明確で見栄えがよくないので、もう少し書きます。



 #define DO_ONCE(...) \ { \ static bool _do_once_ = ([&] ( ) { __VA_ARGS__ } ( ), true); \ (void)_do_once_; \ }
      
      





これは次のように機能します-コードブロックで、ブール型のローカル静的変数が作成されます。これは、「カンマ」演算子を使用して、2段階で初期化されます。



1.括弧演算子を使用して、ラムダが呼び出されます。



 [&] ( ) { __VA_ARGS__ }
      
      





これは、スコープ内にあるすべてを参照によってキャプチャし、ユーザーが__VA_ARGS__に「パック」された引数を介してDO_ONCEマクロに渡した式を実行します定義済みマクロ__VA_ARGS__を使用すると、コンマ(プリプロセッサが解析段階で引数の区切り文字と見なす)が含まれている場合でも、ブロック内のすべてのコードを保存できます。



2.変数_do_once_はtrueに設定されます(割り当てられた値と変数の型自体は役割を果たしません。プログラムで占有されているサイズはカウントしません)。 エントリ「(void)_do_once_;」 未使用の変数に関する警告を避けるために必要です。



この時点で、変数の初期化が完了し、このコードを超えて実行されることはありません。これは達成する必要があったものです。



アプローチの短所:



-C ++ 11標準が必要、

-DO_ONCEブロックごとに1つの変数を作成する必要があります。



長所:



-読みやすさ、シンプルな構文。

-ブロック内のステートメントの数とタイプに制限はありません(サイクルがDO_ONCEブロックボディの外側にある場合はbreakを入力し、DO_ONCEがスイッチ内にある場合はcaseラベルを続行しないでください)。

-DO_ONCE呼び出しのスコープで使用可能な変数と関数を、引数として渡す追加コストなしで機能する機能。

-変数_do_once_をオーバーライドするエラーが発生するリスクはありません。 ブロックの本体では、外側のスコープからこの名前を単純に置き換えます。



使用された文献:

» ラムダ式

» 可変引数リストを持つマクロ



All Articles