1. ホーム
  2. c++

const-correctness はコンパイラに最適化の余地を与えるか?

2023-09-05 21:01:32

質問

可読性が向上し、プログラムがエラーになりにくくなることはわかりましたが、性能はどの程度向上するのでしょうか?

ついでに言うと、参照と const のポインタはどう違うのでしょうか?メモリへの格納方法が違うと思うのですが、どうなんでしょう?

どのように解決するのですか?

[編集: OK、この質問は私が最初に考えたよりも微妙です]。

pointer-to-constまたはreference-of-constを宣言することは、コンパイラが何かを最適化するのに役立つことはありません。 (この回答の一番下にある更新を参照してください)。

また const の中で識別子がどのように使われるかを示すだけです。 スコープ 宣言は、その宣言のスコープ内で識別子がどのように使用されるかを示すだけであり、基盤となるオブジェクトが変更できないことを示すものではありません。

例です。

int foo(const int *p) {
    int x = *p;
    bar(x);
    x = *p;
    return x;
}

コンパイラは *p への呼び出しによって変更されないと仮定することはできません。 bar() というのは p は(例えば)グローバルなintへのポインタである可能性があり bar() はそれを修正するかもしれません。

の呼び出し元についてコンパイラが十分に知っている場合、 その呼び出し元は foo() の内容を知っていて bar() を証明することができます。 bar() を変更しない *p であれば は、const 宣言がなくてもその証明を行うことができます。 .

しかし、これは一般的に言えることです。 なぜなら const は宣言のスコープ内でのみ効果を持つため、コンパイラはそのスコープ内でポインタや参照をどのように扱っているかをすでに見ることができます。つまり、根本的なオブジェクトを変更していないことをすでに知っているのです。

ですから、要するに、すべての const は間違いを防いでくれるのです。 コンパイラがまだ知らないことは何も教えてくれませんので、最適化には無関係です。

を呼び出す関数についてはどうでしょうか? foo() ? のように。

int x = 37;
foo(&x);
printf("%d\n", x);

コンパイラはこれが 37 と表示されることを証明できますか? foo()const int * ?

いいえ、たとえ foo() がconstへのポインタを取るとしても、constらしさをキャストしてintを変更するかもしれません(これは ではなく 未定義の動作です)。 ここでもまた、コンパイラは一般にいかなる仮定も立てることができません。 foo() について十分に知っていて、そのような最適化を行うのであれば、たとえ const .

唯一の const が最適化を可能にするのは、このような場合だけです。

const int x = 37;
foo(&x);
printf("%d\n", x);

ここでは x を何らかのメカニズムで修正すること(例えば、それへのポインタを取って const をキャストすること)は、未定義の振る舞いを呼び出すことになります。 ですから、コンパイラはあなたがそれをしないと仮定して、定数37をprintf()に伝搬させることができるのです。 このような最適化は、あなたが const . (実際には、決して参照を取らないローカル変数は恩恵を受けません。なぜなら、コンパイラはそのスコープ内であなたがそれを変更したかどうかをすでに見ることができるからです)。

(a) const ポインタはポインタであり、(b) const ポインタは NULL に等しいことがあります。 内部表現(つまりアドレス)が同じである可能性が高いというのは正しいです。

[更新] です。

として クリストフ がコメントで指摘しているように、私の回答は不完全です。 restrict .

C99規格の6.7.3.1 (4)項にはこうあります。

Bの各実行中、LをPに基づいて&Lした任意のlvalueとする。 Lが指定するオブジェクトXの値にアクセスするために使用され、Xも(何らかの手段で)変更される場合。 の場合,次の要件が適用される。Tはconst-qualifiedであってはならない。...

(ここでBは、TへのリストリクトポインタであるPがスコープ内にある基本ブロックである)

ですから、もしCの関数 foo() はこのように宣言されます。

foo(const int * restrict p)

...すると、コンパイラが を修正しないものとします。 *p が生きている間は p -- すなわち、実行中に foo() -- の実行中です。そうでなければ動作が未定義になってしまうからです。

ですから、原理的には restrict をpointer-to-constと組み合わせることで、上で却下された最適化の両方が可能になります。 実際にそのような最適化を実装しているコンパイラはあるのでしょうか? (少なくとも GCC 4.5.2 はそうではありません)。

以下のことに注意してください。 restrict は C 言語にのみ存在し、C++ には存在しません (C++0x にも存在しません)。