C ++ - deallocated pointer

I am trying to store objects with pointer elements in std :: vector. As I understand it, when push_back is called, a temporary copy of the passed object is created and sent to the vector internal memory, and then it is destroyed. So I wrote a copy constructor like below:

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 (Frame2D framework) is a structure that just contains 2D coordinates

Segment is a custom class:

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

      

In some function, I fill in a vector:

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

      

And the final conclusion:

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

      

Errors occur in the segment descriptor, but I have allocated two pointer items with a new one in the constructor. Can you help me?

+3


source to share


2 answers


Segment

breaks the rule of three . It lacks a custom copy constructor and copy assignment operator. Whenever you make a copy of one, you get a double delete.

One fix could follow the rule of three and write a copy constructor and a copy operator. But I won't recommend it. Instead, I recommend the zero rule instead . No need to create custom destructors or custom copy constructors anywhere. Just give up the idea of ​​using dynamic memory allocation for nothing.



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


source


Yes, I agree that the missing constructor copy and assignment operator were the root cause of the problem. The "zero rule" solves the problem.

We might want to build objects on the heap (especially if a class like segment is a heavy object in terms of memory layout). In this case, using a smart pointer would be a good idea. This will also take care of the memory reallocation. This also satisfies the "Zero Rule"



The above example is solved with smart pointers:

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


source







All Articles