2012-02-08 16 views
2

私は構造体をシリアル化しようとしていますが、とプログラムがクラッシュした:私はこのコードを持つ2つの問題を参照してください「ダブルフリーまたは破損」が発生するのはなぜですか?

*** glibc detected *** ./unserialization: double free or corruption (fasttop): 0x0000000000cf8010 *** 

#include <iostream> 
#include <cstdlib> 
#include <cstring> 

struct Dummy 
{ 
    std::string name; 
    double height; 
}; 

template<typename T> 
class Serialization 
{ 
    public: 
     static unsigned char* toArray (T & t) 
     { 
      unsigned char *buffer = new unsigned char [ sizeof (T) ]; 
      memcpy (buffer , &t , sizeof (T)); 
      return buffer; 
     }; 

     static T fromArray (unsigned char *buffer) 
     { 
      T t; 
      memcpy (&t , buffer , sizeof (T)); 
      return t; 
     }; 
}; 

int main (int argc , char **argv) 
{ 
    Dummy human; 
    human.name = "Someone"; 
    human.height = 11.333; 

    unsigned char *buffer = Serialization<Dummy>::toArray (human); 

    Dummy dummy = Serialization<Dummy>::fromArray (buffer); 

    std::cout << "Name:" << dummy.name << "\n" << "Height:" << dummy.height << std::endl; 

    delete buffer; 

    return 0; 
} 
+1

'new T []'の代わりに 'std :: vector 'を使用してください。 – GManNickG

答えて

4

  1. をあなたがで未定義の動作を起動しています別の場所にstd::stringを含むstructを入力してください。 memcpy純粋な構造体ではないクラス(たとえば、std::string)であれば、あらゆる種類の問題を引き起こす可能性があります。この特定のケースでは、問題の一部は、std::stringが、文字列の実際の内容を含む文字のバッファへの内部ポインタを格納することがあると考えています。 memcpystd::stringの場合は、文字列を複製する文字列の通常のコピーコンストラクタをバイパスします。代わりに、std::stringの2つの異なるインスタンスがポインタを共有するようになりました。したがって、それらが破壊されると、文字バッファを削除しようとし、あなたが見ているバグを引き起こします。あなたがやっていることをやり遂げる以外に、簡単な修正はありません。基本的に危険です。

  2. new[]でメモリを割り当てていますが、deleteでメモリを削除しています。配列削除演算子delete[]を使用してこのメ​​モリを削除する必要があります。この場合、通常のdeleteを使用すると未定義の動作が発生し、このクラッシュが発生する可能性があります。

は、この情報がお役に立てば幸い!

+0

基本的に、彼の 'Serialization'クラスは、' enable_if > 'の散水が必要です。新しい "is_trivially_copyable"。 –

0

toArrayコールでstringの内部バッファをコピーしています。 fromArrayで逆シリアル化すると、dummyに2番目の文字列が作成されます。この文字列は、humanという同じバッファを所有していると考えられます。

2

memcpy()のデータ要素にstd::string(実際には、いずれも非PODデータ型)のデータは使用できません。 std::stringクラスは、実際の文字列データを動的に割り当てられたバッファに格納します。 memcpy()の内容がstd::stringになると、内部的に割り当てられたポインタが破棄され、すでに解放されているメモリにアクセスすることになります。

あなたはに宣言を変更することによって、あなたのコードの作品を​​作ることができる:固定サイズnameバッファの欠点を持っている、しかし

struct Dummy 
{ 
    char name[100]; 
    double height; 
}; 

。動的にサイズをnameに維持する場合は、ストレートメモリコピーを行わないより高度なtoArrayfromArrayの実装が必要です。

0

std :: stringにはおそらくポインタが文字列データを含むバッファに格納されています。 toArray(人間)を呼び出すと、文字列のデータへのポインタを含むDummyクラスの文字列をmemcpy()しています。そして、新しいDummyオブジェクトをmemcpy()で直接作成すると、最初のオブジェクトと同じ文字列データを持つ新しい文字列オブジェクトが作成されます。あなたが知っている次のことは、ダミーが破壊され、ポインタのコピーが破壊された後、人間が破壊され、BAMが2倍の空きを得ました。

一般に、このようにmemcpyを使用してオブジェクトをコピーすると、見たような問題が発生します。おそらくちょうど氷山の先端になるだろう。代わりに、シリアライズしたいクラスごとにある種のマーシャリング関数を明示的に実装することを検討することもできます。

また、便利なテキストベースの形式にシリアル化できるC++のjsonライブラリを調べることもできます。 JSONプロトコルは、ソケット経由で送信するオブジェクトをシリアル化するカスタムネットワークプロトコルでよく使用されます。

関連する問題