【问题标题】:vector.erase error, cannot delete incomplete typevector.erase 错误,无法删除不完整的类型
【发布时间】:2018-01-02 03:01:36
【问题描述】:

好的,所以我正在尝试创建一个 Actor-Behaviour 系统,但我遇到了一些不完整类型的问题,基本上,当我尝试杀死一个 Actor 时,它告诉我类 Actor 是一个不完整类型。

所以我的结构如下:

Planet-> Vector of all Actors
Actor-> Vector of all Behaviors
Behaviour-> Game Logic

首先,我们有一个 Behavior 类,它有一个对它的actor(将它添加到它的集合中的actor)的引用,一个保存它的类型的字符串,以及用于游戏逻辑的函数:init(在启动时调用)和滴答(每帧调用):

class Actor;

class Behaviour
{
  protected:
    Actor* actor;
  public:
    string type;
    Behaviour();
    ~Behaviour();
    virtual void Init(); // virtual because every component needs to override them
    virtual void Tick();
}

然后我们有 Actor 类,它包含指向其所有行为的唯一指针向量、指向其行星的指针、唯一 ID、名称和游戏逻辑函数,用于循环遍历所有行为并执行游戏逻辑!

// Actor.h
class Planet;

class Actor
{
  private:
    unsigned id;
    string name;
    vector< unique_ptr< Behaviour > > allBehaviours;
  protected:
    Planet* planet;
  public:
    Actor();
    ~Actor();
    void Init(); // Go through all the behaviors and call their Inits and Ticks
    void Tick();

    template <typename T, typename ...Args>
    void AddBehaviour(Args && ...args); // Creates and adds a new Behaviour of type T to the allBehaviours vector

    template <typename T>
    T& GetBehaviour(std::string type); // Loops through all the Behaviours, and returns the Behaviour whose type is the same as type

// Actor.cpp

#include "Planet.h"
#include "Behaviour.h"
#include "Actor.h"

// Implement Functions

那是 Actor.h,Actor.cpp 实现了这些功能,包括 Planet.h,然后是 Behaviour.h,然后是 Actor.h!

现在,Planet 类包含一个指向其所有 Actors 的唯一指针的向量、一个名称和一个用于其 Actors 的唯一 ID 生成器:

// Planet.h

class Actor;

class Planet
{
    private:
      unsigned idCounter = 0;
      string name;
      vector< unique_ptr< Actor > > allActors;
    public:
      unsigned GetNewID();
      void Init();
      void Tick(); // Used to loop through all the Actors

      void AddActor(Actor* newActor); // adds a new Actor to the list of all Actors
      void KillActor(int id); // loops through all the Actors and when it finds an Actor whose unique id is matching the id variable it erases it from the allActors vector

}

// Planet.cpp

#include "Public.h"
#include "Actor.h"
#include "Planet.h"

    Planet::KillActor(int id){
        unsigned i = 0;
        for (auto& a : allActors) {
            if (a->GetID() == id)
                allActors.erase(allActors.begin() + i);
            i++;
        }
    }

    // Other Functions

我还有一个 Public.h 文件,其中包含 iostream、内存、向量等内容!但不包括我创建的文件!

还有一个名为 Win 的类,它有一个 unique_ptr 的集合 并且在 Public.h 中有一个名为 win 的公共变量(包含在任何地方),每次构建一个 Planet 时,它都会被推送到该集合,并且 Win 类有一个指向最后一个构建的 Planet 的指针,所以每次 Actor 都是构造,这条线被调用:

{
 // other stuff
 win.GetCurrentPlanet()->AddActor(this); 
}

我已经测试过这个结构并且它工​​作成功,我可以拥有多个行星并从一个跳转到另一个,指向 Actors 的指针可以正常工作,指向 Behaviors 的指针也可以正常工作!

现在问题出在我调用 KillActor 函数时,它会正确循环所有 Actor,找到我想要杀死的 Actor,然后当我对该 Actor 调用擦除时,它会将我发送到文件内存,并告诉我我的程序已触发断点:

void operator()(_Ty *_Ptr) const _NOEXCEPT
    {   // delete a pointer
    static_assert(0 < sizeof (_Ty),
        "can't delete an incomplete type");
    delete _Ptr; // Here is the breakpoint, it is trying to delete the Actor I inputed 
    }
};

我不明白为什么它给了我这个错误,我很确定我有一个非常可靠的包含和前向声明结构。

编辑 1:

好的,所以我做了一个测试,我禁用了 Tick 功能(它现在什么都不做),我像这样调用 KillActor:

int main() {

    Planet b = Planet("B");

    Actor bactor = Actor();

    bactor.AddBehaviour<TestA>();

    b.KillActor(0); // This still results in the same incomplete type error!

    do
    {
        win.changed = false;
        win.GetCurrentPlanet()->Init();
        while (win.gameRunning)
        {
            win.Tick();
            //win.GetCurrentPlanet()->Tick(1);
            if (win.changed)
                break;
        }
    } while (win.changed);

    win.Quit();

    return 0;
}

【问题讨论】:

  • Actor 它给了我“无法删除不完整类型”错误!复制粘贴所有错误文本,不要解释它,然后尝试缩短它。
  • 您无法从仍在迭代的容器中擦除。您的 killActor 函数是未定义的行为。尝试像 here 一样擦除删除。
  • @Hello 由于它触发了一个断点,这意味着它显然是一个运行时问题,而不是编译时问题,您是否使用调试器来调查调用堆栈,相关的值变量等?
  • “不能删除不完整的类型”部分是一个红鲱鱼。它在一个静态断言中;如果失败,您的程序将拒绝编译。你编译得很好,但是遇到了运行时错误。在运行时,没有不完整的类型。
  • @DanielH 我明白了,谢谢你的信息,你也看到我的最后编辑了吗?这让我认为这与迭代无关!我会尝试虚拟析构函数,看看会发生什么!

标签: c++ pointers vector actor incomplete-type


【解决方案1】:

您无法从仍在迭代的容器中擦除。您的 killActor 函数是未定义的行为。尝试像here一样擦除删除

你有虚函数但没有虚析构函数。修复它。

【讨论】:

  • 这似乎不是问题,问题是Planet类将Actor视为类Actor;但是我不知道为什么,因为我已经正确地包含了所有内容并且实施正在 Planet.cpp 上进行!
  • 如果在最后一个元素上进行擦除,则可以擦除。如果没有,内部代码(例如“erase at begin + pos”)将尝试使用错误的迭代器。
  • @manni66 我也试过禁用 Tick 函数并调用 KillActor,在任何循环之前,还是一样!
  • @Ripi2 我更新了一个新示例,请查看。
猜你喜欢
  • 2021-06-24
  • 2011-05-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多