36
36

More than 5 years have passed since last update.

C / C++ 最初の一度だけ実行する関数

Last updated at Posted at 2018-10-03

概要

この関数何回か呼ばれるけど、この部分一回だけ実行したいなぁ・・・
ってことがまれによくあるので、解決方法を変態度が低い方から紹介していく。

1.グローバル変数フラグ

一番原始的な方法。
野蛮とも言う。
むしろ変態度が高いかもしれない。
名前空間を汚染するからやめたほうがいい。
というかやめろ。

#include <iostream>
void f(){ // 一度だけ実行したい関数
  std::cout << "hello" << std::endl;
}

bool IsFirst = true;
main(){
  for(int i;i < 10;i++){
    if( IsFirst ){
      f();
      IsFirst = false;
    }
  }
}

2.static変数フラグ

一番一般的かもしれない。

#include <iostream>
void f(){ // 一度だけ実行したい関数
  std::cout << "hello" << std::endl;
}

main(){
  static bool IsFirst = true; 
  for(int i;i < 10;i++){
    if( IsFirst ){
      f();
      IsFirst = false;
    }
  }
}

3.std::call_onceを利用( c++のみ )

マルチスレッド対応。
お行儀がよい。

#include <iostream>
#include <mutex>
void f(){ // 一度だけ実行したい関数
  std::cout << "hello" << std::endl;
}

main(){
  for(int i;i < 10;i++){
    static std::once_flag flag;
    std::call_once( flag, f );
  }
}

4.static変数の初期化を利用

マニアック過ぎ。
でも、一番スマート(だと思う)。

#include <iostream>
void f(){ // 一度だけ実行したい関数
  std::cout << "hello" << std::endl;
}

main(){
  for(int i;i < 10;i++){
    // static変数の初期化は最初の一度しか実行されない。
    static bool CallOnce = [](){ f();return true; }(); // 右辺はラムダ式の実行
  }
}

5.マクロで定義

4で紹介した方法の応用。
__LINE__でユニークな名前を生成してるのがミソ。

#include <iostream>
void f(){
  std::cout << "f" << std::endl;
}
void g(){
  std::cout << "g" << std::endl;
}
void h(){
  std::cout << "h" << std::endl;
}

#define CAT_(a,b) a##b
#define CAT(a,b) CAT_(a,b)
#define do_once(f) static bool CAT(DO_ONCE_,__LINE__)=[](){f();return true;}();

main(){
  for(int i;i < 10;i++){
    do_once( f ); // f,g,h がそれぞれ一回ずつ呼ばれる
    do_once( g );
    do_once( h );
  }
}

任意の引数の関数を呼ぶには、ラムダ式に包んでやるといい。

do_once([](){ function( 1,2,3,"abc"); });

6.おまけ N回実行

5で紹介した方法の応用。


#include <iostream>
void f(){
  std::cout << "f" << std::endl;
}

#define CAT_(a,b) a##b
#define CAT(a,b) CAT_(a,b)
#define do_times(f,n) static int CAT(DO_ONCE_CTR,__LINE__)=n;\
                       if(CAT(DO_ONCE_CTR,__LINE__)>0){\
                         f();\
                         CAT(DO_ONCE_CTR,__LINE__) --;\
                       }\

main(){
  for(int i;i < 10;i++){
    do_times( f, 5 );// f が5回実行される
  }
}
36
36
7

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
36
36