-2

コピー コンストラクターが原因であると思われるセグメンテーション エラーが発生しています。ただし、このような例はオンラインのどこにも見つかりません。浅いコピーと深いコピーについて読んだことがありますが、このコピーがどのカテゴリに該当するかわかりません。誰でも知っていますか?

MyObject::MyObject{
    lots of things including const and structs, but no pointers
}
MyObject::MyObject( const MyObject& oCopy){
    *this = oCopy;//is this deep or shallow?
}
const MyObject& MyObject::operator=(const MyObject& oRhs){
    if( this != oRhs ){
        members = oRhs.members;
        .....//there is a lot of members
    }
    return *this;
}
MyObject::~MyObject(){
    //there is nothing here
}

コード:

const MyObject * mpoOriginal;//this gets initialized in the constructor

int Main(){
    mpoOriginal = new MyObject();
    return DoSomething();
}

bool DoSomething(){
    MyObject *poCopied = new MyObject(*mpoOriginal);//the copy
    //lots of stuff going on
    delete poCopied;//this causes the crash - can't step into using GDB
    return true;
}

編集: operator= とコンストラクターを追加

解決済み: 間違ったツリーを鳴らすと、同じオブジェクトに対して delete を 2 回呼び出す関数になってしまいました

4

7 に答える 7

2

コピー コンストラクターでこのような代入演算子を使用することは、通常はお勧めできません。これにより、すべてのメンバーがデフォルトで構築され、それらが割り当てられます。暗黙的に生成されたコピー コンストラクターに依存するか、メンバー初期化子リストを使用してコピーが必要なメンバーをコピーし、適切な初期化を他のメンバーに適用する方がはるかに優れています。

クラス メンバーの詳細がなければ、セグメンテーション違反の原因を判断するのは困難です。

于 2011-08-25T16:33:11.850 に答える
1

コードによると、元のオブジェクトを作成していません...次のようなポインターを作成しているだけです: const MyObject * mpoOriginal;

そのため、コピーは作成された新しいオブジェクトに不正なデータを使用しています...

于 2011-08-25T16:32:06.793 に答える
0

セグメンテーション違反の正確な原因については直接的な答えはありませんが、ここでの従来の知識は3つのルールに従うことです。つまり、コピーコンストラクタ、代入演算子、またはデストラクタのいずれかが必要な場合は、すべてを実装する方が適切です。それらのうちの3つc ++ 0xは移動セマンティクスを追加します。これにより「4のルール」になりますか?)。

次に、それは通常逆です-コピー割り当て演算子はコピーコンストラクターの観点から実装されます-コピーとスワップのイディオム

于 2011-08-25T16:37:33.823 に答える
0
MyObject::MyObject{
    lots of things including const and structs, but no pointers
}

浅いコピーと深いコピーの違いは、動的メモリへのポインターがある場合にのみ意味があります。これらのメンバー構造体のいずれかがそのポインターのディープ コピーを実行していない場合は、それを回避する必要があります (方法は構造体によって異なります)。ただし、すべてのメンバーにポインターが含まれていないか、ポインターのディープ コピーが正しく行われている場合、コピー コンストラクター/代入は問題の原因ではありません。

于 2011-08-25T17:08:28.120 に答える
0

あなたがしていることは、コピーコンストラクターに代入演算子を使用させることです(定義していないようです)。率直に言って、コンパイルできることに驚いていますが、すべてのコードを表示していないため、コンパイルできる可能性があります。

通常の方法でコンストラクターをコピーしてから、同じ問題が発生するかどうかを確認してください。「たくさんのこと...しかし、ポインターが表示されない」というあなたの言うことが本当なら、コピーコンストラクターをまったく作成するべきではありません。削除してみてください。

于 2011-08-25T16:32:18.177 に答える
0

わお....

MyObject::MyObject( const MyObject& oCopy)
{
    *this = oCopy;//is this deep or shallow?
}

どちらでもない。代入演算子の呼び出しです。
オブジェクトの構築が完了していないため、これはおそらく賢明ではありません (完全に有効ですが)。ただし、代入演算子をコピー コンストラクターの観点から定義する方がより伝統的です (copy and swap idium を参照)。

const MyObject& MyObject::operator=(const MyObject& oRhs)
{
    if( this != oRhs ){
        members = oRhs.members;
        .....//there is a lot of members
    }
    return *this;
}

基本的には問題ありませんが、通常、代入の結果は con ではありません。
ただし、この方法で行う場合は、例外を安全にするために処理を少し分割する必要があります。次のようになります。

const MyObject& MyObject::operator=(const MyObject& oRhs)
{
    if( this == oRhs )
    {
        return *this;
    }
    // Stage 1:
    // Copy all members of oRhs that can throw during copy into temporaries.
    // That way if they do throw you have not destroyed this obbject.

    // Stage 2:
    // Copy anything that can **not** throw from oRhs into this object
    // Use swap on the temporaries to copy them into the object in an exception sage mannor.

    // Stage 3:
    // Free any resources.
    return *this;
}

もちろん、copy and swap idum を使用してこれを行う簡単な方法があります。

MyObject& MyObject::operator=(MyObject oRhs)  // use pass by value to get copy
{
    this.swap(oRhs);
    return *this;
}

void MyObject::swap(MyObject& oRhs)  throws()
{
    // Call swap on each member.
    return *this;
}

デストラクタで何もすることがない場合は、それを宣言しないでください (仮想である必要がない限り)。

MyObject::~MyObject(){
    //there is nothing here
}

ここでは、ポインター (オブジェクトではない) を宣言しているため、コンストラクターは呼び出されません (ポインターにはコンストラクターがないため)。

const MyObject * mpoOriginal;//this gets initialized in the constructor

ここでは、オブジェクトを作成するために new を呼び出しています。
これを実行してもよろしいですか?動的に割り当てられたオブジェクトは破棄する必要があります。表向きは削除を使用しますが、通常は C++ ではスマート ポインター内にポインターをラップして、所有者がオブジェクトを正しく自動的に破棄するようにします。

int main()
{ //^^^^   Note main() has a lower case m

    mpoOriginal = new MyObject();
    return DoSomething();
}

しかし、おそらく動的オブジェクトは必要ないでしょう。必要なのは、スコープ外になると破棄される自動オブジェクトです。また、おそらくグローバル変数を使用しないでください (パラメーターとして渡すと、グローバル状態に関連付けられている副作用を使用してコードが機能します)。

int main()
{
     const MyObject  mpoOriginal;
     return DoSomething(mpoOriginal);
}

オブジェクトを作成するだけでコピーを作成するために new を呼び出す必要はありません (コピーするオブジェクトを渡します)。

bool DoSomething(MyObject const& data)
{
    MyObject   poCopied (data);     //the copy

    //lots of stuff going on
    // No need to delete.
    // delete poCopied;//this causes the crash - can't step into using GDB
    // When it goes out of scope it is auto destroyed (as it is automatic).

    return true;
}
于 2011-08-25T18:28:28.267 に答える
-1

それは、あなたが何をするかに応じて、どちらかoperator=です。ここで魔法が起こります。コピー コンストラクターは単に呼び出しているだけです。

自分で定義しなかった場合はoperator=、コンパイラが合成し、浅いコピーを実行しています。

于 2011-08-25T16:31:11.750 に答える