3

2つの構造体AとBがあるとします。これらには共通の構造体Cがあります。reinterpret_castをAに、またはBをCに呼び出しても安全かどうかを知りたいのですが、そうでない場合は、パフォーマンスに影響を与えずに呼び出す方法はありますか?

struct C
{
    string m_c1;
    int32_t m_c2;
    double m_c3;
    string m_c4;
};

struct A
{
    C m_a1;
    string m_a2;
    int32_t m_a3;
};

struct B
{
    C m_b1;
    string m_b2;
    int32_t m_b3;
    double m_b4;
};
int main(int argc,char *argv[])
{
        A a;
        a.m_a1.m_c1="A";
        a.m_a1.m_c4="AA";

        B b;
        b.m_b1.m_c1="B";
        b.m_b1.m_c4="BB";

        C* pc = reinterpret_cast<C*>(&a);
        cout << pc->m_c1 << " " << pc->m_c4 << endl;

        pc = reinterpret_cast<C*>(&b);
        cout << pc->m_c1 << " " << pc->m_c4 << endl;

        return 1;
}
4

2 に答える 2

3

Mike DeSimoneが指摘しているように、クラスはクラスstringであることが保証されていないstandard-layoutため、クラスCはそうではありませんstandard-layout。つまり、メモリレイアウトの保証はまったくありません。したがって、安全ではありません。文字列をに変更した場合にのみ、安全である(const) char*ことが保証されます。

それでも、クラスのレイアウトが同じであり(メンバーの順序を変更したり、メンバーのアクセス指定子を変更したりすることはできません)、クラスにvtableがない場合にのみ安全です。これは、このような場合に「安全」です。コンパイラが希望する動作を表示するコードを生成する方法。

これは、ソフトウェア開発者がめったに与えることができないという2つの保証です。また、このように書かれたコードは理解しにくいです。別の開発者(または1か月後の同じ開発者)がこのコードを無視して(または単に理解していない)、必要な変更を行うと、突然コードが壊れて、手元のエラーを見つけるのが難しくなります。

Aおよびは、 (またはの一部のメンバー)Bへのアクセスを提供するクラスです。より読みやすく、したがってより安全なソリューションは次のとおりです。CC

  • Aとの両方のアクセサを作成しますB。これはおそらくインライン化され、パフォーマンスの低下は発生しません。
  • 継承の理由がある場合は、単純な継承を使用してください。Aand B is-a ClassThatHasACまたはandis - a仮想関数がない限り、ここでもパフォーマンスの問題は発生しない可能性がありますA。どちらの場合も、アクセサはおそらくパフォーマンスコストなしであなたに利益を提供します。B C

最初にいくつかのシンプルで読みやすいコードを作成し、パフォーマンスを測定します。このCアクセスにコストがかかりすぎる場合は、最適化してください。しかし、最適化がキャストトリックの再解釈に要約される場合は、このブービートラップを誰も踏まないように、周囲に警告サインがたくさんあることを確認してください。

于 2013-01-03T07:38:27.720 に答える
2

なぜCからA、Bの両方を継承し、static_cast代わりに使用しないのですか?より安全/よりクリーンである必要があります。

実際、あなたの場合、キャストはまったく必要ありません。AまたはBのptrsをに割り当てることができるはずです。C*

于 2013-01-03T07:06:23.957 に答える