конструктор копирования — освобожденный указатель не был выделен

Я пытаюсь сохранить объекты, которые имеют указатели членов в 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, но я назначил двум членам указателя новый в конструкторе. Не могли бы вы мне помочь?

3

Решение

Segment нарушает правило трех. В нем отсутствует определяемый пользователем конструктор копирования и оператор копирования. Всякий раз, когда вы делаете копию одного, вы получаете двойное удаление.

Одним из исправлений может быть следование правилу трех и написание конструктора копирования и оператора назначения копирования. Но я не буду рекомендовать это. Я буду рекомендовать следующее правило нуля вместо. Там нет необходимости для пользовательских деструкторов или пользовательских конструкторов копирования нигде. Просто отказаться от идеи использования динамического выделения памяти для нуля.

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
}
4

Другие решения

Да, я согласен, что отсутствующий конструктор копии & Оператор присваивания был основной причиной проблемы. «Правило нуля» действительно решает проблему.

Мы можем захотеть построить объекты в куче (особенно если класс, подобный сегменту, является тяжелым объектом с точки зрения разметки памяти). В этом случае было бы неплохо использовать умный указатель. Это также позаботится о выделении памяти. Это также удовлетворяет «правилу нуля»

Приведенный выше пример решается с помощью умных указателей:

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;
}
0