C ++ - 被释放的指针未被分配

时间:2013-01-22 11:03:56

标签: c++ copy-constructor allocation

我正在尝试在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 个答案:

答案 0 :(得分:4)

Segment违反了the rule of three。它缺少用户定义的复制构造函数和复制赋值运算符。每当你复制一个副本时,你最终会得到双重删除。

一个修复可能遵循三个规则并编写复制构造函数和复制赋值运算符。但我不会推荐这个。我建议改为关注the rule of zero。任何地方都不需要自定义析构函数或自定义复制构造函数。只是放弃使用动态内存分配的想法。

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
}

答案 1 :(得分:0)

是的,我确实同意丢失的复制构造函数&amp;赋值运算符是问题的根本原因。 “零规则”确实解决了这个问题。

我们可能想要在堆上构造对象(特别是如果像块这样的类在内存布局方面是一个沉重的对象)。在这种情况下,使用智能指针将是一个好主意。这也将负责内存解除分配。这也满足了“零规则”

上面的例子是使用智能指针解决的:

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