コンパイラはプライベートデータメンバーを最適化することを許可されていますか?

Dec 08 2020

コンパイラが、潜在的な友人を含め、クラスの(プライベート)メンバーが使用されないことを証明できる場合、標準では、コンパイラがクラスのメモリフットプリントからこのメンバーを削除することを許可していますか?

コンパイル時に保護されたメンバーまたはパブリックメンバーにはこれが不可能であることは自明ですが、プライベートデータメンバーに関しては、そのような証明を作成できる場合があります。


関連する質問:

  • パブリック、プライベート、保護の舞台裏(この質問に火をつけた)
  • C ++コンパイラは参照されていないローカルオブジェクトを最適化できますか(自動オブジェクトについて)
  • 静的変数は常にメモリを使い果たしますか?(静的オブジェクトについて)

回答

31 PeterCordes Dec 08 2020 at 23:19

理論的には可能ですが(未使用のパブリックメンバーとともに)、私たちが慣れている種類のコンパイラエコシステムでは不可能です(個別にコンパイルされたコードをリンクできる固定ABIを対象としています)。未使用のメンバーの削除は、個別のライブラリを禁止するプログラム全体の最適化でのみ実行できます1

他のコンパイルユニットは同意する必要があるかもしれませんが、メンバー関数の動作の実装がプライベートメンバーに依存していないことを確認することに依存してsizeof(foo)いる.h場合、それはあなたが導き出すことができるものではありません。

C ++は、ライブラリを実行する方法ではなく、実際には1つのプログラムのみを指定することを忘れないでください。ISO C ++が指定する言語は、(もちろん)私たちが慣れている実装のスタイルと互換性が.cppあり.hますが、すべてのファイルとファイルを一度に受け取り、単一の自己完結型の拡張不可能な実行可能ファイルを生成する実装も可能です。

実装を十分に制約すると(固定ABIなし)、as-ifルールのプログラム全体の積極的な適用が可能になります。


脚注1:コンパイラがクラスで宣言されたすべてのメンバー関数の定義をすでに確認できる場合は、ライブラリを許可する方法として、「またはコンパイル中の他のコードにサイズ情報を何らかの方法でエクスポートする」ことを追加しました。しかし、@ PasserByの回答は、個別にコンパイルされたライブラリは、最終的に外部から見える副作用(I / Oなど)を生成する方法で宣言されたプライベートメンバーを使用したものである可能性があることを指摘しています。したがって、それらを完全に除外する必要があります。

それを考えると、そのような最適化の目的では、パブリックメンバーとプライベートメンバーは同等です。

17 KonradRudolph Dec 08 2020 at 22:26

クラスの(プライベート)メンバーが使用されないことをコンパイラーが証明できる場合

プライベートメンバー他のコンパイルユニットで使用できるため、コンパイラはそれを証明できません。具体的には、これは、Johannes Schaubによって最初に説明されたように、標準の[temp.spec] / 6に従ったテンプレート引数のメンバーへのポインタのコンテキストで可能です。

したがって、要約すると、いいえ、コンパイラは、パブリックまたは保護されたメンバー(as-ifルールに従う)以外のプライベートデータメンバーを最適化してはなりません。

11 PasserBy Dec 08 2020 at 22:30

いいえ、アクセス制御システムを合法的に破壊できるためです。

class A
{
    int x;
};

auto f();

template<auto x>
struct cheat
{
    friend auto f() { return x; }
};

template struct cheat<&A::x>;  // see [temp.spec]/6

int& foo(A& a)
{
    return a.*f();  // returns a.x
}

コンパイラは、Aが最初に使用されたときにABIを修正する必要があり、将来のコードがアクセスする可能性があるかどうかを知ることができないためx、のメモリを修正してAを含める必要がありますx