6

私は最近、D の構造体とクラスに関するこの記事を読んでいて、ある時点で著者が次のようにコメントしています。

...これは構造体の完璧な候補です。その理由は、ALLEGRO_CONFIG へのポインターという 1 つのメンバーしか含まれていないためです。これは、ポインターのサイズにすぎないため、気にせずに値で渡すことができることを意味します。

これは私に考えさせました。本当にそうですか?「無料で」構造体を渡していると信じていると、いくつかの隠れた落とし穴がある可能性がある状況がいくつか考えられます。

次のコードを検討してください。

struct S
{
    int* pointer;
}

void doStuff(S ptrStruct)
{
    // Some code here
}

int n = 123;
auto s = S(&n);
doStuff(s);

s が doStuff() に渡されるとき、(構造体にラップされた) 単一のポインターが関数に渡されるのは本当にすべてですか? 頭のてっぺんから、構造体の型情報だけでなく、メンバー関数へのポインターも渡されるようです。

もちろん、クラスは常に参照型であるため、これは問題になりませんが、構造体の値渡しセマンティクスは、上記のような余分な「隠し」データが関数に渡されることを示唆していますint への構造体のポインター。これにより、プログラマーは、実際には 8 バイト ポインターと関数への他のいくつかの 8 バイト ポインターを渡しているときに、(64 ビット マシンを想定して) 8 バイト ポインターを渡していると考える可能性があります。さらに、オブジェクトの typeinfo のバイト数です。不注意なプログラマーは、意図したよりもはるかに多くのデータをスタックに割り当てています。

私はここで影を追いかけていますか、それとも単一の参照で構造体を渡し、疑似参照型である構造体を取得していると考えている場合、これは有効な懸念事項ですか? Dには、これを防ぐメカニズムがありますか?

4

2 に答える 2

6

この質問は、ネイティブタイプのラッピングに一般化できると思います。たとえば、ラップしてintのように動作するSafeInt型を作成できますが、整数のオーバーフロー条件をスローします。

ここには2つの問題があります。

  1. コンパイラーは、ネイティブ型と同様にコードを最適化しない場合があります。

    たとえば、intをラップしている場合は、オーバーロードされた算術演算子を実装する可能性があります。十分にスマートなコンパイラーはこれらのメソッドをインライン化し、結果のコードはintの場合と同じです。あなたの例では、ダムコンパイラが何らかの不器用な方法で逆参照をコンパイルしている可能性があります(たとえば、構造体の開始のアドレスを取得し、ポインタフィールドのオフセット(0)を追加してから、それを逆参照します)。

    さらに、関数を呼び出すときに、コンパイラーは他の方法で構造体を渡すことを決定する場合があります(たとえば、最適化が不十分であるか、ABI制限があるため)。これは、たとえば、コンパイラが構造体のサイズに注意を払わず、すべての構造体を同じように扱う場合に発生する可能性があります。

  2. structDの型は、関数で宣言した場合、実際に非表示のメンバーを持つ可能性があります。

    たとえば、次のコードは機能します。

    import std.stdio;
    
    void main()
    {
        string str = "I am on the stack of main()";
    
        struct S
        {
            string toString() const { return str; }
        }
    
        S s;
        writeln(s);
    }
    

    Sがmain()のスタックフレームへの隠しポインタを保存するため、これは機能します。static宣言の前にプレフィックスを付けることで、構造体に非表示のポインターを持たせないようにすることができます(例static struct S)。

于 2012-11-10T06:27:54.120 に答える
5

非表示のデータは渡されません。Astructは、その中で宣言されているもの (および必要に応じてパディング バイト) だけで構成され、他には何もありません。すべてstaticであるため、型情報とメンバー関数情報を渡す必要はありません。astructは別の から継承できないため、structポリモーフィズムはありません。

于 2012-11-10T06:22:40.977 に答える