2016-06-23 3 views
0

私はバイナリモードでファイルに保存し、次のクラスがあります:asdポインタの内容はに印刷されているプログラム終了時に私の新しい割り当てポインタが自動的に削除されるのはなぜですか?

int main() 
{ 
    { 
     lol kar; 
     kar.age = 17; 
     kar.name = "Blabla"; 

     ytxt("class").Write(std::string((char*)&kar, sizeof(kar))); //Saves the class in binary mode 
    } 

    lol * asd; 

    { 
     std::string stClass = ytxt("class").Read();//reads the file in binary 
     asd = (lol*)new char[stClass.length()];//asd is now allocated with new 
     memcpy_s(asd, stClass.length(), stClass.c_str(), stClass.length());//copy the content of the file into the class 
    } 

    std::cout << "Name: " << asd->name << std::endl;//output 
    std::cout << "Age: " << asd->age << std::endl; 

    asd->age = 79; 
    std::cout << "Age: " << asd->age << std::endl; 

    delete asd;//I cannot delete it as lol 
    //delete (char*)asd;//works but lol destructor is not called 
    system("pause"); 
} 

:私はこれを持っている私のメインに今

class lol 
{ 
public: 
    ~lol() { 
     std::cout << "destucted" << std::endl; 
     system("pause"); 
    } 

    int age; 
    std::string name; 
}; 

をコンソールでは、ポインタが削除され、デストラクタが呼び出されます。最後に例外がスローされます。

asdポインタを削除しないと、すべて正常に動作していますが、asdポインタのデストラクタが呼び出されません。私はポインタがnew charとして割り当てられていると私はそれをnew charとして削除する必要があることを知っているが、削除操作がlolのデストラクタを呼び出す別の方法はありますか?

+0

として保存することができます。文字列を正しくシリアル化していますか?または単にポインタをダンプする。 –

+2

なぜオブジェクトを 'new lol()'ではなく 'new char [stClass.length()]'として作成しますか? – GMichael

+4

これは、誰かが非PODタイプを簡単にブロブ管理しようとする場合に、数千もの同様の質問に加わることになります。そして悲しいことは、そうしようとする試みが言葉遣い、タイトル、コードサンプルにばらつきがあることです。何百もの重複のうちの1つを自明に見つけることはほとんど不可能です。 – WhozCraig

答えて

1

いくつかのC++構造体だけが生のバイトとして書き込まれ、読み込まれ、合理的な方法で動作します。そのように動作する種類は、「普通の古いデータ」、または略してポッドと呼ばれます。 (C++ 11では、より細かい粒度の概念に分解しましたが、それは詳細です。)

ポッド、バーチャル、デストラクタ、コンストラクタ、組み込み型、またはintのような組み込み型またはポインタと配列を含む構造体またはクラス(デフォルト以外のものと同じもの)は、古い古いデータです。

これらをビットストリームとして読み書きするには、少なくとも半分の意味があります。

ポインタが含まれている場合、指し示されたもののアドレスはプログラムの再起動後も存続しませんので、避けてください。

std::stringは含まれておらず、それを含むものもありません。

ファイルから保存/ロードするには、シリアライゼーションの問題を確認する必要があります。多くの技術がありますが、どれも無料ではありません。

いくつかの出力アーカイブタイプput_hereに対して、無料のsave(put_here, X const& _関数を定義するのが簡単です。次に、サポートする各タイプのオーバーロードを作成します。 loadについても同じ操作を行います。複合型の場合、各要素をセーブ/ロードするだけです。

バージョン管理用のタグなどを追加することは、簡単なコードでも役に立ちます。

文字列のようなシーケンスコンテナの場合は、 `ytxt`は何save(here, str.size()); for (auto&&c:str)save(here, c);

4
ytxt("class").Write(std::string((char*)&kar, sizeof(kar))); 

この行は、バイトのダンプを保存します。しかし、あなたはできませんバイトのダンプを読み込んで、再びあなたのクラスの適切なインスタンスであることを期待します。これは、バイナリのシリアル化の仕組みではありません。これはPODタイプでのみ有効です(おそらくその正確なラインではないでしょう)。データを保存して後でロードする場合は、別の方法が必要です。

プログラム内の他のすべての問題は、正しいデータがあるはずのバイトガベージを持つことになります。

3

デストラクタを修正しても、このコードは動作しません。ポインタを含むオブジェクトのバイトを格納し、そのオブジェクトを別のメモリに復元しようとすると、正しくありません。

あなたのlolクラスにはstd::stringがあり、文字列の実際のバイトへのポインタを格納します。 karのバイトをファイルにコピーすると、実行中のプログラムからポインタが格納され、文字列自体の内容は保存されません。

ファイルからlolのインスタンスを復元すると、そのポインタはkarのデストラクタによって割り当て解除されたメモリを指しています。これは未定義の動作です。

オブジェクトをシリアル化するアプローチを変更する必要があります。あなたが現在持っているアプローチは救済できません。

注:バイトの配列として割り当てられたメモリにクラスを配置状況は配置newオペレータが必要です。新しい配置後にクリーンアップを行う方法については、this Q&Aを参照してください。

+0

基本的に 'std :: string'を静的' char'配列で置き換え、ポインタを削除する前に呼び出す必要のある関数でデストラクタを置き換える必要があります(デストラクタが必要な場合)。そうですか? – terrakuh

+0

@terrakuhこの変更を行う柔軟性があれば、コンストラクタ/デストラクタなしで動作します。 – dasblinkenlight

2

あなたのlolクラスには複雑なオブジェクトであり、内部メモリ管理を持つstd :: stringが含まれているので、実際のオブジェクトではなくファイルからのランダムなバイトを削除しようとすると結果になりますメモリ破損/クラッシュ

関連する問題