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

Posted

技术标签:

【中文标题】C++ - 未分配被释放的指针【英文标题】:C++ - pointer being freed was not allocated 【发布时间】:2013-01-22 11:03:55 【问题描述】:

我正在尝试将具有指针成员的对象存储在 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

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

【问题讨论】:

你为什么还要使用new?我认为这里没有必要。如果您只使用值而不是指针,那么代码将可以正常工作(并且更简单)。您甚至不需要实现任何复制构造函数、复制赋值或析构函数。 可能与您的问题无关,但默认 ctor 未初始化点和段。这将在调用 dtor 时崩溃。 诊断与代码不匹配。代码中的任何地方都没有说“Segment BASE CONSTRUCTOR”。这只是浪费我们的时间。花时间和精力确保代码和输出匹配。 抱歉复制粘贴错误,我将 BASE 替换为 DEFAULT 指向许多指针的方法。正如@R.MartinhoFernandes 所说,存储值。你的生活会轻松很多。 【参考方案1】:

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

【讨论】:

感谢您的帮助。事实上,我真的不知道什么时候需要使用动态分配,因此我认为我过度使用了它。我会看一些关于这个的文档;) 如何理解你的答案中的双重删除? @deepsky 没有双重删除。 如果我只是用vector保存原始类型,即int,类指针,就不会有违反三规则的风险吧?【参考方案2】:

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

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

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

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;

【讨论】:

以上是关于C++ - 未分配被释放的指针的主要内容,如果未能解决你的问题,请参考以下文章

Unique_ptr:被释放的指针在放入列表时未分配

被释放的指针未分配,即使它之前已分配

C: 被释放的 malloc 错误指针未被分配

未分配被释放的指针。复杂 malloc 历史帮助

这个错误是什么意思? malloc:***对象0x103f000的错误:未分配被释放的指针

C 和 C++:释放已分配指针的一部分