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 坐标的结构

Segment 是一个自定义类:

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

在段析构函数中引发了错误,但我在构造函数中为两个指针成员分配了一个新成员。你能帮我吗?

4

2 回答 2

4

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
}
于 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 回答