3

std::vector にポインター メンバーを持つオブジェクトを格納しようとしています。私が理解している限りでは、push_back が呼び出されると、渡されたオブジェクトの一時コピーが作成され、ベクターの内部メモリに送信され、その後破棄されます。したがって、以下に示すようにコピーコンストラクターを作成しました。

class MeltPoint
{
public:
    MeltPoint();
    MeltPoint(b2Vec2* point);
    MeltPoint(b2Vec2* point, Segment* segment, bool intersection);
    MeltPoint(MeltPoint const& copy);
    MeltPoint& operator= (const MeltPoint& m);
    ~MeltPoint();
private:
    b2Vec2* point;
    Segment* segment;
    bool intersection;
};

MeltPoint::MeltPoint()
{
    CCLog("MeltPoint DEFAULT CONSTRUCTOR");
}

MeltPoint::MeltPoint(b2Vec2* point)
{
    CCLog("MeltPoint CONSTRUCTOR");
    this->point = new b2Vec2();
    *(this->point) = *point;
    this->segment = new Segment();
    this->intersection = false;
}

MeltPoint::MeltPoint(b2Vec2* point, Segment* segment, bool intersection)
{
    this->point = point;
    this->segment = segment;
    this->intersection = intersection;
}

MeltPoint::MeltPoint(MeltPoint const& copy)
{
    CCLog("MeltPoint COPY");
    point = new b2Vec2();
    *point = *copy.point;

    segment = new Segment();
    *segment= *copy.segment;
}

MeltPoint& MeltPoint::operator= (const MeltPoint& m)
{
CCLog("MeltPoint ASSIGNMENT");
    *point = *m.point;
    *segment = *m.segment;
    return *this;
}

MeltPoint::~MeltPoint()
{
    CCLog("MeltPoint DESTRUCTOR");
    delete this->point;
    delete this->segment;
}

b2Vec2 (Box2D フレームワーク) は、単純に 2D 座標を保持する構造体です。

セグメントはカスタム クラスです。

class Segment
{
public:
    Segment();
    Segment(b2Vec2* firstPoint, b2Vec2* secondPoint);
    ~Segment();

private:
    b2Vec2* firstPoint;
    b2Vec2* secondPoint;
};

Segment::Segment()
{
    CCLog("Segment DEFAULT CONSTRUCTOR");
    this->firstPoint = new b2Vec2(0, 0);
    this->secondPoint = new b2Vec2(0, 0);
}

Segment::Segment(b2Vec2* firstPoint, b2Vec2* secondPoint)
{
    CCLog("Segment CONSTRUCTOR");
    this->firstPoint = firstPoint;
    this->secondPoint = secondPoint;
}

Segment::~Segment()
{
    CCLog("Segment DESTRUCTOR");
    delete firstPoint;
    delete secondPoint;
}

いくつかの関数では、ベクトルを設定しています:

void someFunction()
{
    vector<MeltPoint> randomVertices;
    randomVertices.push_back(MeltPoint(new b2Vec2(190, 170))); //10
    randomVertices.push_back(MeltPoint(new b2Vec2(70, 110))); //9
}

そして最終的な出力:

MeltPoint CONSTRUCTOR
Segment DEFAULT CONSTRUCTOR
MeltPoint COPY
Segment DEFAULT CONSTRUCTOR
MeltPoint DESTRUCTOR
Segment DESTRUCTOR
MeltPoint CONSTRUCTOR
Segment DEFAULT CONSTRUCTOR
MeltPoint COPY
Segment DEFAULT CONSTRUCTOR
MeltPoint COPY
Segment DEFAULT CONSTRUCTOR
MeltPoint DESTRUCTOR
Segment DESTRUCTOR
MeltPoint DESTRUCTOR
Segment DESTRUCTOR
test(1074,0xac7d9a28) malloc: *** error for object 0x844fd90: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
test(1074,0xac7d9a28) malloc: *** error for object 0x844fda0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug

エラーは Segment デストラクタで発生しますが、コンストラクタで new を使用して 2 つのポインタ メンバーを割り当てました。助けてください。

4

2 に答える 2

4

Segment三つのルールに違反しています。ユーザー定義のコピーコンストラクターとコピー代入演算子がありません。1つのコピーを作成するたびに、二重の削除が発生します。

1つの修正は、3つのルールに従い、コピーコンストラクターとコピー割り当て演算子を作成することです。しかし、私はそれをお勧めしません。代わりにゼロのルールに従うことをお勧めします。カスタムデストラクタやカスタムコピーコンストラクタはどこにも必要ありません。動的メモリ割り当てを無駄に使用するという考えをあきらめてください。

class MeltPoint
{
public:
    MeltPoint();
    MeltPoint(b2Vec2 const& point);
    MeltPoint(b2Vec2 const& point, Segment const& segment, bool intersection);

private:
    b2Vec2 point;
    Segment segment;
    bool intersection;
};

MeltPoint::MeltPoint(b2Vec2 const& point)
: point(point), segment(), intersection(false) {}

MeltPoint::MeltPoint(b2Vec2 const& point, Segment const& segment, bool intersection)
: point(point), segment(segment), intersection(intersection) {}

class Segment
{
public:
    Segment();
    Segment(b2Vec2 const& firstPoint, b2Vec2 const& secondPoint);

private:
    b2Vec2 firstPoint;
    b2Vec2 secondPoint;
};

Segment::Segment()
: firstPoint(0, 0), secondPoint(secondPoint) {}

Segment(b2Vec2 const& firstPoint, b2Vec2 const& secondPoint)
: firstPoint(firstPoint), secondPoint(secondPoint) {}

void someFunction()
{
    vector<MeltPoint> randomVertices;
    randomVertices.push_back(MeltPoint(b2Vec2(190, 170))); //10
    randomVertices.push_back(MeltPoint(b2Vec2(70, 110))); //9
}
于 2013-01-22T11:20:01.600 に答える
0

はい、コピーコンストラクタと代入演算子の欠落が問題の根本的な原因であることに同意します。「ゼロのルール」は問題を解決します。

ヒープ上にオブジェクトを構築したい場合があります(特に、セグメントのようなクラスがメモリレイアウトの点で重いオブジェクトである場合)。その場合、スマートポインタを使用することをお勧めします。これにより、メモリの割り当て解除も処理されます。これは「ゼロの法則」も満たします

上記の例は、スマートポインターを使用して解決されます。

void CCLog(const char* const X)
{
    std::cout << X << endl;
}

struct b2Vec2 {};

class Segment
{
public:
    Segment();
    Segment(b2Vec2* firstPoint, b2Vec2* secondPoint);
    ~Segment();

private:
    std::shared_ptr<b2Vec2> firstPoint;
    std::shared_ptr<b2Vec2> secondPoint;
};

class MeltPoint
{
public:
    MeltPoint();
    MeltPoint(b2Vec2* point);
    MeltPoint(b2Vec2* point, Segment* segment, bool intersection);
    MeltPoint(MeltPoint const& copy);
    MeltPoint& operator= (const MeltPoint& m);
    ~MeltPoint();
private:
    std::shared_ptr<b2Vec2> point;
    std::shared_ptr<Segment> segment;
    bool intersection;
};

MeltPoint::MeltPoint()
{
    CCLog("MeltPoint DEFAULT CONSTRUCTOR");
}

MeltPoint::MeltPoint(b2Vec2* point)
{
    CCLog("MeltPoint CONSTRUCTOR");
    this->point = std::make_shared<b2Vec2>();
    this->point.reset(point);

    this->segment = std::make_shared<Segment>();
    this->intersection = false;
}

MeltPoint::MeltPoint(b2Vec2* point, Segment* segment, bool intersection)
{
    this->point = std::make_shared<b2Vec2>();
    this->point.reset(point);

    this->segment = std::make_shared<Segment>();
    this->segment.reset(segment);
    this->intersection = intersection;
}

MeltPoint::MeltPoint(MeltPoint const& copy)
{
    CCLog("MeltPoint COPY");
    this->point = copy.point;
    this->segment = copy.segment;
    this->intersection = copy.intersection;

}

MeltPoint& MeltPoint::operator= (const MeltPoint& m)
{
    CCLog("MeltPoint ASSIGNMENT");
    point = m.point;
    segment = m.segment;
    return *this;
}

MeltPoint::~MeltPoint()
{
    CCLog("MeltPoint DESTRUCTOR");
}



Segment::Segment()
{
    CCLog("Segment DEFAULT CONSTRUCTOR");
    this->firstPoint = std::make_shared<b2Vec2>();
    this->secondPoint = std::make_shared<b2Vec2>();
}

Segment::Segment(b2Vec2* firstPoint, b2Vec2* secondPoint)
{
    CCLog("Segment CONSTRUCTOR");
    this->firstPoint = std::make_shared<b2Vec2>();
    this->firstPoint.reset(firstPoint);

    this->secondPoint = std::make_shared<b2Vec2>();
    this->secondPoint.reset(secondPoint);
}

Segment::~Segment()
{
    CCLog("Segment DESTRUCTOR");
}

int _tmain(int argc, _TCHAR* argv[])
{
    vector<MeltPoint> randomVertices;
    randomVertices.push_back(MeltPoint(new b2Vec2())); //10
    randomVertices.push_back(MeltPoint(new b2Vec2())); //9
    return 0;
}
于 2013-01-22T13:42:25.710 に答える