50

C++ の const-correctness に関するすべてのアドバイスを読みましたが、コンパイラがコードを最適化するのに役立つため、(部分的に) 重要であることがわかりました。私が見たことがないのは、コンパイラがこの情報を使用してコードを最適化する方法についての適切な説明であり、カーテンの後ろで何が起こっているかを説明している優れた本でさえありません。

たとえば、コンパイラは const として宣言されているメソッドと、そうではないはずのメソッドをどのように最適化しますか。可変変数を導入するとどうなりますか? それらは const メソッドのこれらの最適化に影響しますか?

4

12 に答える 12

56

const キーワードは、最適化ではなく、主にプログラムのセマンティックのコンパイル チェックのために導入されたと思います。

Herb Sutter は、GotW #81 の記事で、const 参照によってパラメーターを渡すとき、または const 戻り値を宣言するときにコンパイラーが何も最適化できない理由を非常によく説明しています。その理由は、 const が宣言されていても、参照されるオブジェクトが変更されないことをコンパイラが確認する方法がないためです。 const_cast を使用するか、他のコードが同じオブジェクトに対して非 const 参照を持つことができます。

ただし、Herb Sutter の記事を引用すると、次のようになります。

「const」という言葉が実際に何かを意味する場合が [1 つだけ] あります。それは、オブジェクトが定義された時点でオブジェクトが const になる場合です。その場合、コンパイラは多くの場合、そのような「本当にconst」なオブジェクトを読み取り専用メモリに正常に配置できます[...]。

この記事には他にもたくさんのことが書かれているので、読んでおくことをお勧めします。そうすれば、定数最適化についてよりよく理解できるようになります。

于 2008-10-17T14:30:37.427 に答える
35

メソッドを無視して const オブジェクトだけを見てみましょう。コンパイラーは、ここで最適化する機会がはるかに多くあります。オブジェクトが const と宣言されている場合、(ISO/IEC 14882:2003 7.1.5.1(4)):

ミュータブル (7.1.1) と宣言されたクラス メンバーを変更できることを除いて、その有効期間中 (3.8) に const オブジェクトを変更しようとすると、未定義の動作が発生します。

変更可能なメンバーを持つ可能性のあるオブジェクトを無視します。コンパイラは、オブジェクトが変更されないことを自由に想定できるため、大幅な最適化を行うことができます。これらの最適化には、次のようなものを含めることができます。

  • オブジェクトの値を直接機械命令オペコードに組み込む
  • コンパイル時に既知の条件式で const オブジェクトが使用されているために到達できないコードの完全な削除
  • const オブジェクトがループの反復回数を制御している場合のループ展開

これは、実際のオブジェクトが const である場合にのみ適用されることに注意してください。const ポインターまたは参照を介してアクセスされるオブジェクトには適用されません。これらのアクセス パスは const ではないオブジェクトにつながる可能性があるためです (const を介してオブジェクトを変更することも明確に定義されています)。実際のオブジェクトが非 const であり、オブジェクトへのアクセス パスの constness をキャストする限り、ポインター/参照)。

実際には、あらゆる種類の const オブジェクトに対して重要な最適化を実行するコンパイラは存在しないと思います。しかし、プリミティブ型 (int、char など) のオブジェクトの場合、コンパイラはこれらのアイテムの使用を最適化することに非常に積極的である可能性があると思います。

于 2008-10-17T15:41:05.787 に答える
6

手振りが始まる

基本的に、データが修正されるのが早ければ早いほど、コンパイラーはデータの実際の割り当てをより多く動かすことができ、パイプラインが失速しないようになります。

手を振って終了

于 2008-10-17T14:03:08.527 に答える
5

うーん。Const-correctness は、最適化というよりもスタイル/エラー チェックのようなものです。完全な最適化コンパイラは、変数の使用法に従い、変数が事実上 const であるかどうかを検出できます。

それに加えて、コンパイラはあなたが真実を伝えることに依存することはできません.コンパイラが知らないライブラリ関数内で const をキャストしている可能性があります.

そうです、const-correctness は目指す価値のあるものですが、優れた最適化コンパイラーを想定して、それ自体が理解できないことをコンパイラーに伝えません。

于 2008-10-17T14:14:56.243 に答える
3

const 宣言された関数は最適化されません。

const 宣言された関数を呼び出す関数を最適化できます。

void someType::somefunc();

void MyFunc()
{
    someType A(4);   // 
    Fling(A.m_val);
    A.someFunc();
    Flong(A.m_val);
}

ここで Fling を呼び出すには、値 A.m_val を CPU レジスタにロードする必要がありました。someFunc() が const でない場合、Flong() を呼び出す前に値を再ロードする必要があります。someFunc が const の場合、レジスタに残っている値で Flong を呼び出すことができます。

于 2008-10-17T14:11:02.833 に答える
3

メソッドを const として持つ主な理由は、const の正確性のためであり、メソッド自体のコンパイルの最適化のためではありません。

変数が const の場合、(理論的には) 最適化して取り除くことができます。ただし、スコープのみがコンパイラによって表示されます。結局、コンパイラは const_cast を使用して他の場所で変更できるようにする必要があります。

于 2008-10-17T14:13:46.713 に答える
2

これらはすべて真の答えですが、答えと質問は、コンパイラの最適化が実際に重要であるという 1 つのことを前提としているようです。

コンパイラの最適化が重要になるコードは 1 種類だけです。

  • タイトな内側のループ、
  • サードパーティのライブラリとは対照的に、コンパイルするコードでは、
  • 関数またはメソッド呼び出し (非表示のものも含む) を含まない、
  • プログラムカウンターがその時間のかなりの部分を費やす場所

コードの残りの 99% が N 度まで最適化されていても、プログラム カウンターが実際に時間を費やしているコードでのみ問題となるため (サンプリングによって見つけることができます)、大きな違いはありません。

于 2008-12-23T20:23:00.677 に答える
1

オプティマイザーが実際に const 宣言に多くの在庫を入れているとしたら、私は驚かれることでしょう。const-ness をキャストすることになるコードがたくさんあります。これは、プログラマーの宣言に依存して、状態が変化する可能性があると仮定する非常に無謀なオプティマイザーです。

于 2008-10-17T14:15:28.363 に答える
1

const-correctness はドキュメントとしても役立ちます。関数またはパラメーターが const としてリストされている場合、コードの下で値が変更されることを心配する必要はありません (チームの他の誰かが非常にいたずらでない限り)。ただし、ライブラリに組み込まれていなければ、実際に価値があるかどうかはわかりません。

于 2008-12-23T21:25:25.887 に答える
0

const直接最適化が行われる最も明白なポイントは、関数に引数を渡すことです。多くの場合、関数がデータを変更しないようにすることが重要であるため、関数シグネチャの唯一の実際の選択肢は次のとおりです。

void f(Type dont_modify); // or
void f(Type const& dont_modify);

もちろん、ここでの本当の魔法は、オブジェクトの (高価な) コピーを作成するのではなく、参照を渡すことです。しかし、参照が としてマークされていない場合const、これはこの関数のセマンティクスを弱め、マイナスの影響 (エラー追跡が難しくなるなど) をもたらします。したがって、constここで最適化を有効にします。

/EDIT:実際には、優れたコンパイラは関数の制御フローを分析し、引数を変更しないことを判断し、最適化(コピーではなく参照を渡す)自体を行うことができます。constここにあるのはコンパイラのヘルプです。ただし、C++ にはかなり複雑なセマンティクスがあり、そのような制御フロー分析は大きな関数に対して非常にコストがかかる可能性があるため、これをコンパイラに頼るべきではないでしょう。誰かが私をバックアップする/私が間違っていることを証明するデータを持っていますか?

/EDIT2: はい、カスタム コピー コンストラクターが機能するようになると、さらに複雑になります。残念ながら、コンパイラーはこの状況でそれらの呼び出しを省略することが許可されていないためです。

于 2008-10-17T14:58:08.057 に答える
0

このコード、

class Test
{
public:
  Test (int value) : m_value (value)
  {
  }

  void SetValue (int value) const
  {
    const_cast <Test&>(*this).MySetValue (value);
  }

  int Value () const
  {
    return m_value;
  }

private:
  void MySetValue (int value)
  {
    m_value = value;
  }

  int
    m_value;
};

void modify (const Test &test, int value) 
{
  test.SetValue (value);
}

void main ()
{
  const Test
    test (100);

  cout << test.Value () << endl;
  modify (test, 50);
  cout << test.Value () << endl;
}

出力:

100
50

これは、const 宣言されたオブジェクトが const メンバー関数で変更されたことを意味します。C++ 言語に const_cast (および mutable キーワード) が存在するということは、const キーワードは、最適化されたコードを生成する際にコンパイラを支援できないことを意味します。以前の投稿で指摘したように、予期しない結果が生じることさえあります。

原則として:

const != 最適化

実際、これは正当な C++ 修飾子です。

volatile const
于 2008-10-17T15:17:55.367 に答える
-1

const主に最適化可能なコードを記述できるため、コンパイラーの最適化に役立ちます。あなたが投げ込まない限りconst_cast

于 2008-10-17T18:51:09.803 に答える