1

このコードを含むソースファイルファイルをコンパイルするとします。

struct Point
{
    int x;
    int y;
};

struct Size
{
    int x;
    int y;
};

PointSizeは(そのメンバーのメモリレイアウトに関して)まったく同じなので、コンパイラstructはオブジェクトファイルに重複コード(各に1つ)を生成しますか?それが私の最初の質問です。


それでは、ソースコードからを削除し、代わりに次のようにstruct Size定義してみましょう。typedef

typedef Point Size;

コンパイルは今何をしますか?コードを複製しますか(typedefは名前を変更するだけでなく、それ以上のものであるため)?


ここで、次のようなクラステンプレートがあるとします。

template <int UnUsed>
class ConcreteError : public BaseError {
public:
    ConcreteError () :BaseError(), error_msg() {}

    ConcreteError (int errorCode, int osErrorCode, const std::string& errorMessage)
        :BaseError(errorCode, osErrorCode, errorMessage){}
};

そして、このようにいくつかの定義を設定します。

typedef ConcreteError<0> FileError;
typedef ConcreteError<1> NetworkError;
typedef ConcreteError<2> DatabaseError;

テンプレートパラメータint UnUsedはクラスの実装では使用されないため(と仮定してください)、この状況はまったく同じメモリレイアウトを持つ複数のクラスとまったく同じように見えます(との場合と同様struct Pointstruct Size。オブジェクトファイル?

そして、私たちがこのようにしたらどうなるでしょう、

typedef ConcreteError<0> FileError;
typedef ConcreteError<0> NetworkError;
typedef ConcreteError<0> DatabaseError;

typedefで同じインスタンス化されたクラスを使用しているので、この状況はより良いですか?

PS:このクラステンプレートコードはここから取得されます:

C ++のテンプレートプログラミングを使用して基本クラスから派生クラスを作成するにはどうすればよいですか?


実際、コンパイラがソースコードからオブジェクトファイルを生成する方法や、クラス名、メンバー、その他のシンボルなどをどのように処理するのか、私にはわかりません。typedefをどのように処理しますか?これで何をしますか、

typedef int ArrayInt[100];

ArrayIntここに新しいタイプはありますか?オブジェクトファイルにどのコードコンパイラが作成しますか?どこに100保管されていますか?

4

3 に答える 3

2

まず、最初に含めた構造定義のコードは生成されないため、2 つのタイプを比較するのは無意味です。しかし、C++ では型名が重要であるため、 aは astruct Aとは明確に区別して扱われstruct Bます。

typedef型エイリアスを作成するため、typedef された型実際には元の型です (別の型は作成されません)。

ConcreteError<0>とは違うタイプですConcreteError<1>

パラメータがデータレイアウトの点で同一であり、関数が実際の異なるデータで他のサブ関数を呼び出す必要がない場合、コンパイラがファンキーになり、マングルされた関数名を同じコードにエイリアシングすることを妨げるものは何もないと思います型と関数は両方の型と同等のことを行いますが、これが実際に実際に行われているとは思いません。実際には、これを行うコンパイラーがあります (以下の Ben のコメントを参照してください)。

最後の typedef (すべて のエイリアスConcreteError<0>) では、 の「バージョン」がConcreteError1 つだけ作成されます (そのバージョンだけがインスタンス化されるため)。

于 2010-12-17T17:44:09.600 に答える
2

あなたの例からの単一の行は、オブジェクトファイルにコードを生成しません。または、より正確には、データをまったく生成しません。「コード」は単なるプロセッサ命令を意味すると思います。

オブジェクト ファイル内のデータは、コード、静的データ、および定数データの 3 つのセグメントに分割されます。

コードは、インライン関数を除いて、実際の関数定義 (宣言だけでなく関数本体を使用) によって生成されます。インライン関数は、実際に使用されるたびにコードを生成します。テンプレート関数はインスタンス化されるとコードを生成しますが、複数のインスタンス化は通常、コンパイラ、リンカー、またはその両方によって単一のインスタンスに最適化されます。

静的データは、グローバル変数、静的メンバー変数 (クラス内の宣言だけでなく実際の定義)、および静的ローカル変数を定義することによって生成されます。const変数は、静的データ セグメントに移動する修飾子を使用して宣言してはなりません。

定数データは、静的データと同じ種類の変数宣言によって生成されますが、const修飾子、浮動小数点リテラル、文字列リテラル、およびハードウェア プラットフォームによってはさらに多くのリテラルが含まれます。OS はハードウェア レベルで定数データへの書き込みアクセスを実際に許可しない場合があるため、そこに何かを書き込もうとすると、アクセス違反またはセグメンテーション違反でプログラムがクラッシュする可能性があります。

私はそのような低レベルのことの専門家ではないので、何かを見落としているかもしれませんが、全体像をかなりうまく説明できたと思います.

私が本当に何かを見逃していない限り、特に宣言と型定義など、プログラム内でオブジェクト ファイルにデータを生成するものは他にありません。これらは、コンパイラによって内部的に使用されます。そのため、コンパイラは構造体定義を確認すると、それが 2 つの 32 ビット整数で構成されていることを認識します。その構造体を使用する実際のコードを見つけると、2 つの 32 ビット整数で動作するコードを生成する必要があること、それを格納するために少なくとも 8 バイトを割り当てる必要があることなどを認識します。しかし、この情報はすべてコンパイル時に内部的に使用され、実際にはオブジェクト ファイルには入りません。C++ にリフレクションのようなものがあれば、話は別です。

多くの構造体を定義してもオブジェクト ファイルには何も追加されませんが、コンパイラ自体によるメモリ使用量が増加する可能性があることに注意してください。したがって、同一のものを定義すると、コンパイル時にデータの重複が発生しますが、実行時には発生しないと言うかもしれません。

于 2010-12-17T19:39:01.277 に答える
0

いいえ、未使用の PODS でコードが重複することはありません。それらを使用すると、2 つの int と、メモリ内のそれらに割り当てられるパディングが存在する可能性があります。もちろん、それらはすべて同じように見えるため、何と呼びたいかについては議論の余地がありますが、2 つの場所で同じタイプを使用することよりも「重複」ではありません。

いいえ、エイリアスを使用した重複コードはありません。実際にはコードはまったくありません。

おそらく、コンパイラが特定の最適化を使用するかどうかによって異なります。

多分。typedef が異なる翻訳単位で使用されているかどうか、およびコンパイラが重複したインスタンス化を削除するのにどれだけ優れているかによって異なります。

いいえ、int[100] のエイリアスです。

「このコンストラクトからどの程度のマシン コードが生成されるか」という問題は、実装に大きく依存します。

于 2010-12-17T17:50:29.480 に答える