2009-03-24 26 views
4
typedef struct temp 
{ 
     int a,b; 
     char *c; 
     temp(){ c = (char*)malloc(10);}; 
     ~temp(){free(c);}; 
}temp; 

int main() 
{ 
    temp a; 
    list<temp> l1; 
    l1.push_back(a); 
    l1.clear(); 
    return 0; 

} 

セグメンテーション違反が発生しました。Segフォールト後のアイテムがSTLコンテナにプッシュされました

+0

あなたがしなければならない理由がない限り、malloc&freeの代わりに新しい&deleteを使用する習慣を身につけてください。 –

+1

C言語でstructを "typedef"する必要はありません。 – Dan

+2

トップヒント:クラスや構造体を定義するときは、ポインタメンバーでespを宣言し、operator =とcopyコンストラクタをprivateとして宣言します。 "private:temp&operator =(const temp&); temp(const temp&);"コピーが必要なクラスで何かを行うと、コンパイルされず、それらを提供する必要があることがわかります。 –

答えて

27

コピーコンストラクタはありません。

リストに「a」を押すと、コピーされます。 コピーコンストラクタ(cのメモリを割り当て、古いcから新しいcにコピーする)を持たないため、cはaの中の同じポインタであり、リストのaのコピーです。

両方のaのデストラクタが呼び出されます。最初のものが成功し、メモリcが既に解放されているため、2番目のものが失敗します。

コピーコンストラクタが必要です。

何が起こっているか見るには、コンストラクタとデストラクタにいくつかの呪文を入れてコードをステップ実行します。

+0

これまでに誰が落札したことができますか?なぜ私の答えが間違っているのか分かりませんか?ありがとうございました –

+0

私は-1ではありませんでしたが、cは削除されません - オブジェクトを削除してメモリを解放することは同じことではありません。 –

+0

@ペテ:あなたはもちろん正しいです、私の指が私のためにミスした、ありがとう:) –

0

コピーコンストラクタ&代入演算子 - STLコレクションに格納されたものはコピーとして保存され、ベクトルのサイズが変わると再割り当てできます。

コードから、コピーコンストラクタのセマンティクスを正確に見るのは難しいですが、デストラクタが何かを解放できるように、少なくとも何らかのメモリを割り当てるのは無駄です。代入演算子は、クラスの詳細がなくても同じように指定するのは難しいです。

5

ダブルフリー()を避けるには、ディープコピーコンストラクタが必要です。変数の温度クラスa)を指定して、それをリストに追加します。変数がコピーされます。次にリストをクリアすると、内部の要素が破棄され、free()が呼び出されます。次に、変数が破棄され、セグメンテーションフォールトにつながる同じアドレスに対してfree()が再度呼び出されます。

別のバッファをmalloc()してデータをコピーするディープコピークラスの一時変数のコピーコンストラクタが必要です。

3

l1.push_back(a)と呼ぶときに、「a」の第2のコピーがコピー構築されます。その結果、元のmalloc呼び出しからメモリを所有していると考える2つのクラスがあり、2番目のmalloc呼び出しが削除されると、最初のmalloc呼び出しによって削除されたメモリを解放しようとします。

解決策は、クラスのインスタンスが実際にデータを所有していないという事実を扱うコピーコンストラクタを追加することです。通常は、参照カウントの形式を使用することでこれを行います。

0

tempのコピーコンストラクタを定義する必要があります。今すぐあなたがaを押すと何が起こるのかは、aのコピーです。コピー(a2と呼ぶ)はa2.c = a.cと書かれて初期化されます。つまり、aa2の両方が同じメモリブロックを指していることを意味します。それらのデストラクタが呼び出されると、そのメモリブロックは2回freeになり、セグメンテーションエラーが発生します。あなたが投稿したものを考えると

、コピーコンストラクタは、おそらくこのようなものでなければなりません:

temp::temp (temp const &rhs) 
{ 
    this->a = rhs.a; 
    this->b = rhs.b; 
    this->c = (char *) malloc (10); 
    memcpy (this->c, rhs.c, 10); 
} 

これは何cポイントには、常に10文字の長さであることを前提としてい...

1

コピーコンストラクタを追加しない場合は、値のリストの代わりに値のポインタのリストを考慮することができます。

list<temp*> l1; 
l1.push_back(new temp()); 

しかし、メモリリークを防ぐためにリスト内の各オブジェクトを手動で削除する必要があります。

また、構造体のa、bメンバーは初期化されません。注意してください。

3

上記の修正は別として、C++ではmalloc/freeを使用しないでください。あなたの特定のケースでは、私はベクターでいいと思う:

#include <vector> 

typedef struct temp 
{ 
     int a,b; 
     std::vector<char> c; 
     temp(){ c.reserve(10);}; 
}temp; 

int main() 
{ 
    temp a; 
    list<temp> l1; 
    l1.push_back(a); 
    l1.clear(); 
    return 0; 

} 
+0

これは残念な例です。 STLをよく知らない人は、本当にバッファを割り当てるだけで、reserve()はベクトルのサイズを変更する(実際に要素を追加する)と仮定できます。 – sharptooth

+0

私はそれがわかっています。私はpush_backコマンドを使いたいと思っていたので、それをしました。 –

1

コピーコンストラクタに加えて、この場合には、あまりにも=演算子を提供するのが賢明です。それらを削除することをお勧めし

temp(){ c = (char*)malloc(10);}; 
~temp(){free(c);}; 

struct temp { // typedef is implicit in C++ 
    int a,b; 
    char * c; 

    // Constructor 
    temp() { c = malloc(10); } 
    // Destructor 
    ~temp() { free(c); } 
    // Copy constructor 
    temp(const temp & x) { c = malloc(10); setTo(x); } 
    // Operator = 
    temp & operator = (const temp & x) { setTo(x); return *this; } 

    // Initialize THIS to X 
    void setTo(const temp & x) { a = x.a; b = x.b; memcpy(c,x.c,10); } 
}; 
0

このコードのもう一つの問題は、余分なセミコロンです:

temp(){ c = (char*)malloc(10);} 
~temp(){free(c);} 
0

これは「STL」のタグが、不足していたことをどのように皮肉STLの問題が原因です。

+0

「STLの欠如」とは何でしょうか? –

+0

STLを使用すると、malloc()/ free()を呼び出す手間が省けます。また、デストラクタやコピーコンストラクタは必要ありません。そのため、ポストされているソリューションの大部分を処理します。 –