程序已触发断点,0x77239D11 (ntdll.dll) 处未处理的异常:0xC0000374:堆已损坏(参数:0x7726D8D0)

program has triggered a breakpoint, Unhandled exception at 0x77239D11 (ntdll.dll): 0xC0000374: A heap has been corrupted (parameters: 0x7726D8D0)

了解实体组件架构的请跳过解释!

解释:

好的,所以我正在尝试创建一个实体组件系统,但我遇到了一个非常奇怪的问题,直到现在才发生过,基本上我有一个包含一些变量的实体 class (如名称、标签、id)和一个指针向量,它跟踪添加到实体的所有组件,即实体 class,所有组件都派生自组件 class,它有一个类型(char*),以及启动、更新等虚函数,etc.This 是您创建组件的方式:

#pragma once
class printcomponent : public Component {
  printcomponent() : Component("printcomponent"){} // the printcomponent constructor derives from the component constructor which takes a char* as parameter, and sets the component's type to that char*
 void Start(){
 cout << "This is printed on start" << endl;
} 
void Update(){
 cout << "This gets printed every frame" << endl;
}
 ~printcomponent();//destructor
}

我的问题:

好吧,只有当我尝试获取 Rigidbody2d 类型的组件时,我的问题才会出现,这是 "PhysicalObject.cpp",physicalobject 是一种实体类型,它已经有一些组件,比如预制件,所以我不不必总是向实体类型添加相同的组件,例如物理对象:

#include "stdafx.h"
#include "Public.h" // all the public variables are in here, and declared in Public.cpp
#include "PhysicalObject.h"

PhysicalObject::PhysicalObject(float boxwidth, float boxheight, float gscale, bool fixedr, float nDnsity, float nFricton, string name, string tag, bool isactive, bool isstatic) : Entity(name, tag, isactive, isstatic) // so basically the constructor creates an entity
{
    this->AddComponent<Transfrm>(b2Vec2(0.f, 0.f), 0.f, b2Vec2(1.f, 1.f)); // i add a transform component
    this->AddComponent<RigidBody2D>(gscale, fixedr); // i add a rigidbody2d component, there is no problem when adding components
    this->AddComponent<SprtRend>(this); // again spriterenderer component
    trans = this->GetComponent<Transfrm>(); // okay so i have 2 variables for easily accessing specific components, i have one trans for transform, and one rigidb for rigidbody2d, basically calling this instead of getting component is much more efficient !
    rigidb = this->GetComponent<RigidBody2D>(); // this is the line causing me problems, the previous line doesn't cause any problem, but this causes an  Unhandled exception, in the function GetComponent of Entity.h
}

错误指向 "entity.h" getcomponent 函数 Entity.h:

// 添加组件、构造函数等函数。

template <typename T>
T* GetComponent() {
    T t; // so basically this function creates a new given type T and loops through all the components until it finds a matching type
    for (unsigned i = 0; i < AllComponents.size(); i++) {
        if (AllComponents.at(i)->Type == t.Type) { // when debugging in this line, in the 'autos' window, it shows the type as "RigidBody2D", which is fine, but after i continue to the other line, it gives me the unhandled exception and the type of 't' is something like: "/x" and some numbers, which makes no sense, and doesn't occur when getting other components.
            return dynamic_cast<T*>(AllComponents.at(i));
            break;
        }
    }
    cout << "Entity: " << Name << " Does Not Have Component of Type: " << t.Type << endl;
}

// desctructor

最后是RigidBody2d.h文件,里面有rigidbody组件,和其他组件没什么区别,但是还是报错

RigidBody2D.h: // 我将展示所有代码,因为我不确定是什么导致了这个问题,所以如果 post 变得非常长,我深表歉意,另请注意,我已经在我的引擎中实现了 box2d 库,因此其中有一些变量和函数,我认为它们不会导致任何错误。

#pragma once
#include "Component.h"
#include "Transfrm.h" // i need the transform component for the rigidbody because it contains a position, rotation, etc.        

class RigidBody2D : public Component
{
public:
    b2BodyDef bodyDef;
    Transfrm* Trans;
    b2Body* Body;
    float* GScale; // this pointer needs to point to the gravity scale variable of body
    bool* FreezeRot; // this pointer needs to point to the freeze rotation variable of body
    bool IsKinematic;

    void SetGScale(float newgs){
        *GScale = newgs;
    }
    void SetFreezeRot(bool newfr) {
        *FreezeRot = newfr;
    }
    void SetIsKinetic(bool newisk) {
        IsKinematic = newisk;
    }
    RigidBody2D(float gscale = 1.f, bool fixedr = false); // constructor, before i used 2 constructors one with no parameters, but that caused me errors, because the compilier didn't know which constructor to use since they were the same(didn't require parameters)
    ~RigidBody2D();
};

最后 RigidBody2D.cpp:

#include "stdafx.h"
#include "Public.h"
#include "RigidBody2D.h"

RigidBody2D::RigidBody2D(float gscale, bool fixedr) : Component("RigidBody2D")
{
    Trans = new Transfrm(b2Vec2(0.f, 0.f), 0.f, b2Vec2(1.f, 1.f));
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set(Trans->Position.x, Trans->Position.y);
    bodyDef.gravityScale = gscale;
    bodyDef.fixedRotation = fixedr;
    GScale = &bodyDef.gravityScale;
    FreezeRot = &bodyDef.fixedRotation;
    Body = CurrentPhysicsWorld->CreateBody(&bodyDef);
}
RigidBody2D::~RigidBody2D() {
    delete Trans;
    delete GScale;
    delete FreezeRot;
    CurrentPhysicsWorld->DestroyBody(Body);
};

我对巨大的 post 感到非常抱歉,它花了我大约 2 个小时来写,但我已经搜索和调试了 3 天,但仍然找不到解决方案,因为我从来没有遇到过这样的问题,在此先感谢。

对我来说这部分看起来很奇怪:

RigidBody2D::RigidBody2D(float gscale, bool fixedr) : Component("RigidBody2D")
                               ^^^^^^^ gscale is a float
{
    Trans = new Transfrm(b2Vec2(0.f, 0.f), 0.f, b2Vec2(1.f, 1.f));
    bodyDef.type = b2_dynamicBody;
    bodyDef.position.Set(Trans->Position.x, Trans->Position.y);
    bodyDef.gravityScale = gscale;
                           ^^^^
                           Used for initialization of bodyDef.gravityScale 

    bodyDef.fixedRotation = fixedr;
    GScale = &bodyDef.gravityScale;
    ^^^^^^
    Pointer to bodyDef.gravityScale

    FreezeRot = &bodyDef.fixedRotation;
    Body = CurrentPhysicsWorld->CreateBody(&bodyDef);
}
RigidBody2D::~RigidBody2D() {
    delete Trans;
    delete GScale;
    ^^^^^^^^
    Delete of bodyDef member which wasn't created by new        



    delete FreezeRot;
    CurrentPhysicsWorld->DestroyBody(Body);
};

所以在我看来,您正在尝试 delete 并非由 new

创建的内容

一些突出的事情:

GetComponent 并不总是 return 任何东西,这很容易导致未定义的行为。

~RigidBody2D() 中,您正在 delete 创建两个对象 – GScaleFreezeRot – 它们不是使用 new 创建的,但属于通过 bodyDef.
当然,这是未定义的。

这两个是否足以解决你的问题很难猜测。
根据您发布的代码,我怀疑可能还有许多其他类似问题需要查找。

我认为问题在于您如何手动删除 GScaleFreezeRot。在 GetComponent 中,您创建了一个临时对象 T,它将在函数结束时超出范围。如果您搜索 RigidBody 类型,它的析构函数将在函数完成时调用,删除一些指针,应该留给 Box2D 管理

作为解决方法,我建议删除代码帽以删除这 2 个成员,并为每种类型创建一个名为 Type 的静态成员,以便您可以执行以下操作:

T::Type

不必创建临时对象:

T t;
T.type