たとえば、このコードがある場合:
_class SomeDataProcessor
{
public:
bool calc(const SomeData & d1, const SomeData & d2) const;
private:
//Some non-mutable, non-static member variables
}
SomeDataProcessor sdp;
SomeData data1;
SomeData data2;
someObscureFunction(sdp.calc(data1, data2),
sdp.calc(data1, data2));
_
潜在的に同等のコードを考えてみましょう:
_bool b = sdp.calc(data1, data2);
someObscureFunction(b,b);
_
これを有効にするには、calc()
関数がいくつかの要件を満たしている必要があります。この例では、プロパティ__pure_const_formula_
_を呼び出します
__pure_const_formula_
_は:
_pure_const_formula_
_関数のみを呼び出すたとえば、乱数ジェネレーターを呼び出すと、これらの要件に適合しません。
コンパイラは、呼び出された関数を再帰的に掘る必要がある場合でも、最初のコードを2番目のコードに置き換えることができますか?最新のコンパイラはこれを実行できますか?
GCCには、関数にpure
attribute (__attribute__((pure))
として使用)があり、冗長な呼び出しを削除できることをコンパイラーに伝えます。使用されていますstrlen
に。
呼び出される関数がソース形式で利用できない可能性があり、オブジェクトファイル形式には関数が純粋であるかどうかに関するメタデータが含まれていないという事実を考慮して、これを自動的に行うコンパイラーは特に知りません。
はい、絶対に。
たとえば、関数がすべてtrue
を返し、その定義が呼び出し側でコンパイラに見える場合、関数呼び出し全体がおそらく省略され、結果は次のようになります。
someObscureFunction(true, true);
コンパイラが十分な情報を持っているプログラムは、非常に複雑な一連のタスクからおそらく1つまたは2つの命令まで「最適化」されます。さて、実際にメンバー変数を操作すると、オプティマイザーがある程度まで限界に達しますが、変数がprivate
であり、既知の初期値が与えられ、他のメンバー関数によって変更されていない場合、コンパイラーが、既知の値を必要に応じてインライン化できない理由を理解してください。コンパイラは非常にスマートです。
コンパイルされたプログラムは、ソースコード内の行の1対1のマッピングであると考えられますが、これはほとんど真実ではありません。 C++の全体的な目的は、プログラムの実行時にコンピューターが実際に実行することのabstractionであることです。
いいえ、示されたコードを考えると、コンパイラは、提案された最適化に目に見える違いがないことを保証できず、最新のコンパイラは2番目の関数呼び出しを最適化できません。
非常に簡単な例:このクラスメソッドは、乱数ジェネレーターを使用し、結果をプライベートバッファーに保存し、コードの他の部分が後で読み取ります。明らかに、関数呼び出しを削除すると、そのバッファーに配置されるランダムに生成される値が少なくなります。
言い換えると、クラスメソッドがconst
であるからといって、呼び出されたときに観察可能な副作用がないことを意味するわけではありません。
いいえ、この場合、コンパイラはこれを行うことができません。 const
は、メソッドが属するオブジェクトの状態を変更しないことのみを意味します。ただし、同じ入力パラメーターでこのメソッドを複数回呼び出すと、異なる結果が得られる場合があります。たとえば、ランダムな結果を生成するメソッドを考えてください。
はい、最新のCコンパイラは、冗長関数呼び出しifとifを排除できます。このような最適化がas-if元のプログラムのセマンティクスに従いました。たとえば、関数に副作用がなく、戻り値が引数のみに依存している場合、同じ引数を使用して同じ関数を複数回呼び出す必要がないことを意味します。
さて、あなたはconst
について具体的に尋ねました-これは、コーダーではなく、開発者にとって最も有用です。 const
関数はhintsであり、メソッドは呼び出されたオブジェクトを変更せず、const
引数はhints引数が変更されないこと。ただし、関数は(合法的に1)const
ポインタまたはその引数のthis
- nessをキャストします。そのため、コンパイラはそれに依存できません。
さらに、関数に渡されたconst
オブジェクトがその関数内で実際に変更されておらず、const
関数がレシーバーオブジェクトを変更していない場合でも、メソッドは変更可能なグローバルデータに簡単に依存できますそのようなデータ)。たとえば、現在の時刻を返す関数、またはグローバルカウンターをインクリメントする関数を考えます。
したがって、const
宣言は、コンパイラではなくプログラマに役立ちます2。
ただし、コンパイラーは他のトリックを使用して、呼び出しが冗長であることを証明できる場合があります。
pure
およびconst
関数属性を提供します。これらの属性は、関数に副作用がなく、パラメーターのみに依存することをgcc
に通知します(およびpure
の場合はグローバル変数について)。1 通常、オブジェクトが元々const
として定義されていなかった限り。
2 ある意味で、const
definitionsがコンパイラを支援する:const
として定義されたグローバルオブジェクトを読み取り専用セクションに入れることができる実行可能ファイル(そのような機能が存在する場合)およびそれらのオブジェクトが等しい場合(たとえば、同じ文字列定数)を組み合わせます。