0

ポインターが割り当てられているかどうかをチェックするデストラクタがあり、割り当てられている場合は削除します。

ShadeRec::~ShadeRec(){

    cout << "before deleting ShadeRec" << endl;
    if(material){
        cout << material << endl;
        delete material;
        material = NULL;
    }
    cout << "after deleting ShadeRec" << endl;
}

最初のポインターは問題なく通過し、2番目のポインターでプログラムがエラーを表示します。

s で確認したcoutところ、ポインター内に何かがあります。これは、if ステートメントに入ったときに意味があります...では、なぜエラーが発生するのですか?

コンストラクター:

ShadeRec::ShadeRec(World& world)
    :   hit(false),
        material(NULL),
        hitPoint(),
        localHitPoint(),
        normal(),
        ray(),
        depth(0),
        colour(0),
        t(0.0),
        w(world)
{}

ShadeRec::ShadeRec(const ShadeRec& sr)
    :   hit(sr.hit), 
        material(sr.material), 
        hitPoint(sr.hitPoint), 
        localHitPoint(sr.localHitPoint), 
        normal(sr.normal), 
        ray(sr.ray), 
        depth(sr.depth), 
        colour(sr.colour), 
        t(sr.t),
        w(sr.w)
{}

材料演算子=

Material& 
Material::operator= (const Material& rhs) {
    if (this == &rhs)
        return (*this);

    return (*this);
}

Matte は Material の子です:

Matte* matte1 = new Matte;

これらの両方として:

Matte& operator= (const Matte& rhs);

virtual Material* clone(void) const;
4

2 に答える 2

4

ほとんどの場合、これは次のとおりです。

  • materialメンバー変数である場合ShadeRec
  • ShadeRecポインターを取得/設定するコンストラクター
  • copy-ctor が定義されていないか、定義されている場合は、ポインターをコピーするだけで、それが指すオブジェクトの新しいインスタンスを作成しません。
  • のインスタンスが少なくとも 2 つありShadeRecます。パラメータまたは戻り値としてコピーされている可能性があります。
  • 最初の dtor はオブジェクトを削除し、独自のポインタをNULL
  • 2 番目の dtor は別のオブジェクトで動作し、そのポインタはまだ設定されています
  • バム!

見えるようにするにthisは、dtor にも出力すると、別のインスタンスであることがわかりますShadeRec


編集後: 次の行です:

material(sr.material),

単純なポインターをコピーするだけでなく、オブジェクトのコピーを作成する必要があります。別のオプションとして好まれることが多いのはstd::shared_ptr(C++11 を使用できる場合は、それ以外の場合は をチェックしてくださいboost::shared_ptr) を使用することですが、 のコピーはShadeRec同じマテリアル インスタンスを共有することに注意してください。

これまでに示した内容を踏まえて、上記の copy-ctor の行を次のように置き換えます。

material(sr.material->clone()),

そして、それが機能するかどうかを確認してください。

于 2013-03-27T21:27:06.307 に答える
2

問題

ディープ コピー コンストラクターを定義していません。オブジェクトのコピーを作成するとShadeRec、ポインタがコピーされるため、2 つのクラス間で競合が発生します。

次のように使用する場合:

ShadeRec a;
ShadeRec b(a);

どちらのインスタンスにも同じアドレスが含まれています。つまり、最初のインスタンスがポインターを正しく解放した場合、2 番目のインスタンスはそのポインターを解放する必要があります (もう一方のインスタンスによって既に解放されています)。

ソリューション例

正しいディープ コピー コンストラクターの例を次に示します。material動的に割り当てられたMaterialオブジェクトへのポインターであり、Materialクラスに適切に定義されたコピーコンストラクターがあることを考慮します。

ShadeRec::ShadeRec(const ShadeRec& sr)
    :   hit(sr.hit), 
        material(0), // <--- NULL 
        hitPoint(sr.hitPoint), 
        localHitPoint(sr.localHitPoint), 
        normal(sr.normal), 
        ray(sr.ray), 
        depth(sr.depth), 
        colour(sr.colour), 
        t(sr.t),
        w(sr.w)
{
    if (sr.material)
        material = new Material(*(sr.material));
}

適切な代入演算子の書き方の例を次に示します。

Material& 
Material::operator= (const Material& rhs) {
    if (this != &rhs) {
        if (material)
            delete material;
        // make member per member assignments here
        material = new Material(*(rhs.material));
    }
    return (*this);
}

もっと

可能であれば、スマート ポインターを使用する必要があります。スマート ポインターは、C++11 の時点std::shared_ptrで STL として実装されているか、C++11 より前のバージョンでは、boost ライブラリで として利用できますboost::shared_ptr

于 2013-03-27T21:26:50.743 に答える