2

この投稿を読むと、事前に割り当てられたメモリ位置でクラス コンストラクターを呼び出すために C++ の配置ニュースが使用されていることが明らかです。

メモリが既に初期化されている場合、新しい配置または reinterpret_cast のどちらがより適切ですか?

たとえば、フレーム化されたメッセージを表す生のバイト ストリームを TCP ソケットから読み取ったとします。このストリームを framesync に入れ、クラスを表す既知のサイズのバッファーを取得します。これを Message と呼びます。私は、次の 2 つの方法を知っています。

  1. クラスに初期化しないように指示するフラグを受け取るコンストラクターを作成します。「初期化しない」フラグを渡してバッファに新しい配置を行います。

    Message::Message( bool initialize ) 
    {
        //
        // Initialize if requested
        //
        if( initialize )
        {
            Reset( );
        }
    }
    
    void Message::Reset( void )
    {
       m_member1 = 1;
       m_member2 = 2;
    }
    
    Message* message = new ( buffer ) Message( false );
    
  2. reinterpret_cast を使用する

    Message* message = reinterpret_cast< Message* > ( buffer ); 
    

どちらも同じ結果になると思います。どちらがより正確で、よりオブジェクト指向で、より安全で、読みやすく、またはより良いスタイルであるため、どちらが好まれますか?

4

2 に答える 2

11

唯一の意味のあるルールは次のとおりです。

何らかの型のインスタンスがaddressで既に構築されTている場合、既に存在するオブジェクトへのポインターを取得します。areinterpret_cast<T*>(a)

型のインスタンスがaddress にまだ構築されTていない場合は、placement new を使用して、型のインスタンスを address に構築します。aTa

それらは完全に異なる操作です。

質問する必要があるのは、非常に単純です。「オブジェクトは既に存在しますか?」はいの場合は、(キャストを介して) アクセスできます。いいえの場合は、それを構築する必要があります (placement new を介して)

2 つの操作は互いに何の関係もありません。

彼らは異なることをするので、どちらを好むべきかという問題ではありません。あなたが望むことをするものを好むべきです。

于 2012-07-24T16:45:28.503 に答える
1

どちらとも言えません。

新しい配置を使用し、特別な構築方法を使用することは、ハックのように思えます。たとえば、標準では、初期化されていない int クラス メンバーは「不確定な値」を持ち、それにアクセスすると未定義の動作が「発生する可能性がある」と規定されています。int が int として解釈される変更されていない基礎となるバイトの値を想定することは指定されていません。コンストラクターを呼び出す前に、準拠する実装がメモリをゼロで初期化することを妨げるものは何もないと思います。

この reinterpret_cast の使用を明確に定義するには、いくつかのフープをジャンプする必要があります。それでも、結果のオブジェクトを使用すると、厳密なエイリアシング ルールに違反する可能性があります。

より実際には、クラスの実装指定の表現をネットワーク経由で直接送信する場合、互換性のあるレイアウト (互換性のある表現、アライメントなど) を持つ通信システムに依存することになります。

代わりに、たとえば memcpy() と ntoh() を使用してバッファーからデータを既存のオブジェクトのメンバーに取得するなど、実際のシリアル化と逆シリアル化を行う必要があります。

struct Message {
    uint32_t m_member1;
    uint16_t m_member2;
};

extern char *buffer;

Message m;

memcpy(&m.m_member1, buffer, sizeof m.m_member1);
m.m_member1 = ntohl(m.m_member1);
buffer += sizeof m.m_member1;

memcpy(&m.m_member2, buffer, sizeof m.m_member2);
m.m_member2 = ntohs(m.m_member2);
buffer += sizeof m.m_member2;

既存のライブラリを使用するだけでない場合は、おそらく独自のフレームワークにこのようなものをまとめたいと思うでしょう。

この方法では、アラインメントの問題に対処する必要はありません。ネットワーク表現は明確に定義されており、異なる実装間で渡すことができ、プログラムは技術的に未定義の動作を使用しません。

于 2012-07-24T18:38:15.477 に答える