web-dev-qa-db-ja.com

コードを1回だけ実行する方法は?

いくつかの機能を備えたアプリケーションがあります。各関数は、ユーザー入力に基づいて何度でも呼び出すことができます。ただし、関数内でコードの小さなセグメントを実行する必要があるのは、最初にアプリケーションを起動したときに1回だけです。この同じ関数が後で再度呼び出されるときは、この特定のコードを実行してはなりません。コードは VC++。これを処理する最も効率的な方法を教えてください。

20
Darzen

コンストラクター(mainの前に呼び出される)でグローバル静的オブジェクトを使用しますか?またはちょうどルーチンの中に

static bool initialized;
if (!initialized) {
   initialized = true;
   // do the initialization part
}

これが十分に速くない場合はほとんどありません!


補遺

マルチスレッドのコンテキストでは、これでは不十分な場合があります。

pthread_once または constructorfunction __attribute__ of GCC

C++ 11では、 std :: call_once が必要になる場合があります。

<atomic> と宣言しますstatic volatile std::atomic_bool initialized;(ただし、関数を複数のスレッドから呼び出すことができる場合は注意が必要です)。

ただし、これらはシステムで使用できない場合があります。 Linuxで利用可能です!

24

ラムダ関数を使用したコンパクトバージョン:

void foo()
{
    static bool once = [](){
        cout << "once" << endl;
        return true;
    } ();
    cout << "foo" << endl;
}

ラムダ関数内のコードは、静的変数がラムダ関数の戻り値に初期化されるときに1回だけ実行されます。コンパイラがスレッドセーフな静的初期化をサポートしている限り、スレッドセーフである必要があります。

23
Bediver

C++ 11の使用-std::call_once

#include <mutex>

std::once_flag onceFlag;

{
    ....
    std::call_once ( onceFlag, [ ]{ /* my code body here runs only once */ } );
    ....
}
21
Soren

ローカル静的変数を使用できます。

void foo()
{
     static bool wasExecuted = false;
     if (wasExecuted)
         return;
     wasExecuted = true;

     ...
}
16
Abyx

これをしてもらえますか

initと呼ばれるブール型または何らかのデータ型を返す関数がある

私はそれをこのように起こさせました、あなたはそれを起こさせるために静的ブールが必要です

bool init()
{
  cout << "Once " <<endl;
  return true||false;// value isn't matter
}

void functionCall()
{
    static bool somebool = init(); // this line get executed once
    cout << "process " <<endl;
}

int main(int argc, char *argv[])
{
    functionCall();
    functionCall();
    functionCall();

    return EXIT_SUCCESS;
}
5
aah134

@Basileの回答に加えて、ラムダを使用して次のように静的変数をカプセル化できます。

if ([] {
    static bool is_first_time = true;
    auto was_first_time = is_first_time;
    is_first_time = false;
    return was_first_time; } ()) 
{ 
    // do the initialization part
}

これにより、簡単に汎用マクロに変換できます。

#define FIRST_TIME_HERE ([] { \
    static bool is_first_time = true; \
    auto was_first_time = is_first_time; \
    is_first_time = false; \
    return was_first_time; } ())

どこにでも配置できます 必要に応じて

if (FIRST_TIME_HERE) {
    // do the initialization part
}

そして、適切な対策として、 atomics 式を短くして、スレッドセーフにします。

#include <atomic>
#define FIRST_TIME_HERE ([] { \
    static std::atomic<bool> first_time(true); \
    return first_time.exchange(false); } ())
4
John McFarlane

C++ 11以降、静的ローカル変数はスレッドセーフであり、通常ほとんどの場合に十分なので、std::call_once()et al。やり過ぎかもしれません。

これは、C++ 17のinitialization-within -ifおよび std::exchange() を使用する場合に特にエレガントに見えます。

_#include <utility>

void
do_something_expensive_once()
{
    if ( static auto called = false; !std::exchange(called, true) ) {
        do_something_expensive();
    }
}
_

これが頻繁に使用するパターンである場合は、タグタイプを介してカプセル化できます。

_template <typename T>
auto
call_once()
{
    static auto called = false;
    return !std::exchange(called, true);
}

void
do_something_expensive_once()
{
    struct TagForSomethingExpensive final {};

    if ( call_once<TagForSomethingExpensive>() ) {
        do_something_expensive();
    }
}
_

または、関数のアドレス、一意の整数などをテンプレートにすることもできます。

次に、callableをcall_once()などに渡すこともできます。 C++の場合と同様に、可能性は無限大です!

0
underscore_d