2

ねえ、私はドラムマシンに取り組んでいて、ベクトルに問題があります。

各シーケンスにはサンプルのリストがあり、サンプルはベクトルで並べられています。ただし、サンプルがベクトルでpush_backの場合、サンプルのデストラクタが呼び出され、ダブルフリーエラーが発生します。

サンプル作成コードは次のとおりです。

class XSample
{
  public:
    Uint8 Repeat;
    Uint8 PlayCount;
    Uint16 Beats;
    Uint16 *Beat;
    Uint16 BeatsPerMinute;

    XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat);
    ~XSample();

    void GenerateSample();

    void PlaySample();
};

XSample::XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat)
{
    Beats = NewBeats;
    BeatsPerMinute = NewBPM;
    Repeat = NewRepeat-1;
    PlayCount = 0;

    printf("XSample Construction\n");
    Beat = new Uint16[Beats];
}

XSample::~XSample()
{
    printf("XSample Destruction\n");
    delete [] Beat;
}

そして、ベクトル内の各サンプルを作成する「Dynamo」コード:

class XDynamo
{
  public:
    std::vector<XSample> Samples;

    void CreateSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat);
};

void XDynamo::CreateSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat)
{
    Samples.push_back(XSample(NewBeats,NewBPM,NewRepeat));
}

main()は次のとおりです。

int main()
{
    XDynamo Dynamo;

    Dynamo.CreateSample(4,120,2);
    Dynamo.CreateSample(8,240,1);

    return 0;
}

そして、これはプログラムが実行されたときに起こることです:

Starting program: /home/shawn/dynamo2/dynamo 
[Thread debugging using libthread_db enabled]
XSample Construction
XSample Destruction
XSample Construction
XSample Destruction
*** glibc detected *** /home/shawn/dynamo2/dynamo: double free or corruption (fasttop): 0x0804d008 ***

ただし、デストラクタからdelete []を削除すると、プログラムは完全に実行されます。

これを引き起こしているのは何ですか?どんな助けでも大歓迎です。

4

5 に答える 5

8

自明ではないデストラクタがあるため、適切なコピーコンストラクタと代入演算子が必要です(より正確には、クラスがメモリ割り当てをラップするため)。「ビッグ3のルール」を参照してください。


アップデート:

Martin Yorkがコメントで述べたように、この回答は実際には問題の直接の原因に対処するだけですが、リソースを自動的に管理するRAIIクラスメンバーを使用するという、問題を修正するための最良の方法を実際には示唆していません。表面的には(サンプルコードが与えられている場合)、メンバーは手動で割り当てられた配列へのポインターでBeatはなく、可能性があります。メンバーは、クラスが特別なdtor、copy ctor、または代入演算子を必要としないことを許可します。これらのすべてのピースは、メンバーがである場合、自動的にメンバーに提供さstd::vector<>れます。vector<>Beatvector<>

于 2010-05-11T20:00:54.533 に答える
4

問題は、オブジェクトに動的にメモリを割り当てているが、コピーコンストラクタ/代入演算子を宣言していないことです。メモリを割り当てて削除する場合は、コンパイラが生成する4つのメソッドすべてを定義する必要があります。

class XSample
{
    public:
        // Pointer inside a class.
        // This is dangerous and usually wrong.
        Uint16 *Beat;
};

XSample::XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat)
{
    // You allocated it here.
    // But what happens when you copy this object or assign it to another variable.
    Beat = new Uint16[NewBeats];
}

XSample::~XSample()
{
    // Delete here. Turns into double delete if you don't have
    // copy constructor or assignment operator.
    delete [] Beat;
}

あなたがするとき、上記はどうなりますか:

XSample   a(15,2,2);
XSample   b(a);  // Copy constructor called.
XSample   c(15,2,2);

c = a; // Assignment operator called.

これを解決する2つの方法:

  1. コピーコンストラクタ/代入演算子を作成します。
  2. メモリ管理を行う別のオブジェクトを使用してください。

私はソリューション2を使用します(より単純なので)。
それもより良いデザインです。メモリ管理は独自のクラスで行う必要があり、ドラムに集中する必要があります。

class XSample
{
  public:
    std::vector<Uint16> Beat;
};

XSample::XSample(Uint16 NewBeats,Uint16 NewBPM,Uint8 NewRepeat):
        Beat(NewBeats)
{
         // Notice the vector is constructed above in the initializer list.
}

    // Don't need this now.
XSample::~XSample()
{
}

難しい方法でやりたい場合:
オブジェクトの配列を動的に割り当てる

コンパイラのバージョンがここでどのように見えるかを確認したい場合:
他のオブジェクトを含むクラスのC++暗黙的コピーコンストラクタ

于 2010-05-11T22:32:33.447 に答える
2

コンパイラーはデフォルトのコピーコンストラクターを追加しました。これは、のXSample::Beats間にエイリアス化されたことを意味しsamples.push_back(...)ます。おそらく引数からコピーすることによって、XSampleを正しく初期化するコピーコンストラクターを追加する必要がXSample::Beatsあります。

于 2010-05-11T20:00:41.150 に答える
2

vectorはXSample(コンパイラが生成したデフォルトのコピーコンストラクタを使用して)sをコピー構築しているため、コピーを破棄するときに問題が発生します。XSampleベクトルへのポインタを格納するか、適切なコピーコンストラクタを記述できます。

于 2010-05-11T20:00:44.767 に答える
1

何が起こっているのかというとSamples.push_back()、その引数をベクトルにコピーします。XSampleコピーコンストラクターが定義されていないため、コンパイラーは、浅いコピーを実行するデフォルトのコンストラクターを作成します。これはBeat、元のポインタとベクトルのコピーの両方のポインタが同じメモリを指していることを意味します。その後、オリジナルは最後に破棄され、ポインタ push_back()が削除されます。Beat

mainの終わりにDynamo、各要素のデストラクタを呼び出して、が破棄されます。これにより、すでに削除されたBeatポインタが削除され、二重削除エラーが発生します。

于 2010-05-11T20:19:00.233 に答える