18

C / C ++に関数があり、それが最初に実行されたときに特定の方法で動作するとします。そして、他のすべての場合、それは別の方法で動作します(たとえば、以下を参照)。初めて実行した後、ifステートメントは冗長になり、速度が重要な場合は最適化できます。この最適化を行う方法はありますか?

bool val = true; 

void function1() {

   if (val == true) {
      // do something
      val = false; 
   }
   else {
      // do other stuff, val is never set to true again 
   }

}
4

11 に答える 11

17

gcc分岐予測について実装に通知できる組み込み関数があります。

 __builtin_expect 

http://gcc.gnu.org/onlinedocs/gcc/Other-Builtins.html

たとえば、あなたの場合:

bool val = true; 

void function1()
{
    if (__builtin_expect(val, 0)) {
       // do something
       val = false; 
    }
    else {
      // do other stuff, val is never set to true again 
    }
}
于 2012-10-19T21:53:19.800 に答える
16

本当にボトルネックであることが確実な場合にのみ、変更を行ってください。分岐予測ではif、非常に予測可能なパターンであるため、ステートメントはおそらく瞬時です。

つまり、コールバックを使用できます。

#include <iostream>
using namespace std;
typedef void (*FunPtr) (void);
FunPtr method;
void subsequentRun()
{
    std::cout << "subsequent call" << std::endl;
}
void firstRun()
{
    std::cout << "first run" << std::endl;
    method = subsequentRun;  
}
int main()
{
    method = firstRun;
    method();
    method();
    method();
}

出力を生成します:

最初の実行
後続の呼び出し
後続の呼び出し

于 2012-10-19T21:50:08.950 に答える
9

関数ポインタを使用することもできますが、いずれの場合も間接呼び出しが必要になります。

void (*yourFunction)(void) = &firstCall;

void firstCall() {
 ..
 yourFunction = &otherCalls;
}

void otherCalls() {
 ..
}

void main()
{
  yourFunction();
}
于 2012-10-19T21:50:44.180 に答える
4

staticグローバル変数の代わりにメンバー変数を使用できます。

または、最初に実行するコードが将来のすべての使用(ファイルを開くなど)のために何かを変更した場合、その変更をチェックとして使用して、コードを実行するかどうかを判断できます(つまり、ファイルが開いています)。これにより、余分な変数を節約できます。また、エラーチェックに役立つ場合があります-何らかの理由で最初の変更が別の操作によって変更されていない場合(たとえば、ファイルが不適切に削除されたリムーバブルメディア上にある場合)、チェックは変更を再実行しようとする可能性があります。

于 2012-10-19T21:51:14.980 に答える
4

考えられる方法の 1 つは、関数の 2 つの異なるバージョンをコンパイルし (これは、テンプレートを使用してソース内の単一の関数から実行できます)、関数ポインターまたはオブジェクトを使用して実行時に決定することです。ただし、関数が非常に高価でない限り、ポインターのオーバーヘッドは潜在的な利益を上回る可能性があります。

于 2012-10-19T21:47:48.250 に答える
1

コンパイラーは、コンパイル時に既知のもののみを最適化できます。

あなたの場合、の値はval実行時にのみ知られているため、最適化することはできません。

テストは非常に迅速です。if最適化について心配する必要はありません。

于 2012-10-19T21:50:47.810 に答える
1

コードを少しすっきりさせたい場合は、次を使用して変数を関数に対してローカルにすることができますstatic

void function() {
    static bool firstRun = true;
    if (firstRun) {
        firstRun = false;
        ...
    }
    else {
        ...
    }
}

関数に初めて入ると、firstRunはtrueになり、関数が呼び出されるたびにfirstRun変数が前のインスタンスと同じになるように保持されます(その後はfalseになります)。

これは、@ouahのソリューションでうまく使用できます。

于 2012-10-22T14:14:25.090 に答える
0

独立したコンパイラーを維持するには、if() の一部を 1 つの関数とelse{}別の関数でコーディングできます。ほとんどすべてのコンパイラが最適化しますif() else{}- そのため、最も可能性が高いのはelse{} - したがって、時折の実行可能コードをコード化しif()、残りを別の関数で呼び出します。else

于 2012-10-20T06:57:11.437 に答える
0

g++ (および msvc と確信している) などのコンパイラは、最初の実行時にプロファイル データを生成し、そのデータを使用してどの分岐がたどられる可能性が最も高いかを推測し、それに応じて最適化することをサポートします。gcc を使用している場合は、-fprofile-generateオプションを確認してください。

予想される動作は、else が最初に順序付けられるようにコンパイラがその if ステートメントを最適化することです。これにより、後続のすべての呼び出しで jmp 操作が回避され、そこにない場合と同じくらい高速になります。それ以外のどこかに(したがって、「if」ステートメントを飛び越える必要がなくなります)

于 2012-10-19T21:47:43.337 に答える
0

できることの 1 つは、ロジックをオブジェクトのコンストラクターに入れ、それを定義することstaticです。そのようなstaticオブジェクトがブロック スコープで発生した場合、そのスコープの実行が最初に行われるときにコンストラクターが実行されます。一度だけのチェックは、コンパイラによって発行されます。

staticオブジェクトをファイル スコープに置くこともできます。オブジェクトmainは呼び出される前に初期化されます。

おそらくあなたは C++ クラスを効果的に利用していないので、私はこの答えを出しています。

( に関してC/C++は、そのような言語はありません。C と C++ があります。C++ としてもコンパイルする必要がある C で作業していますか (非公式に「クリーン C」と呼ばれることもあります)、それとも本当に C++ で作業していますか?)


「Clean C」とは何ですか? 標準 C との違いは何ですか?

于 2012-10-20T00:48:10.457 に答える