【问题标题】:Returned vector defined as "std::vector<<error-type>, std::allocator<<error-type>>>返回的向量定义为“std::vector<<error-type>, std::allocator<<error-type>>>
【发布时间】:2018-01-15 19:45:59
【问题描述】:

我正在尝试将结构向量从一个对象返回到另一个对象。我的第一个想法是返回对向量的引用。两个目标文件都包含有问题的结构(侦听器结构)和执行返回的函数如下所示:

vector<Listener>* Component::GetListeners() {
    vector<Listener> listeners;
    for (int i = 0; i < listenerSize; i++) {
        Listener listener = { id, static_cast<EventType>(Component::listensFor[i]) };
        listeners.push_back(listener);
    }
    return &listeners;
}

构造一个listener的向量,然后返回向量的地址

当我在下一个函数中收到指针时出现问题:

void Entity::AddComponent(Component c) {
    components.push_back(c);
    vector<Listener> *listeners = c.GetListeners();
    for (int i = 0; i < listeners->size; i++) {

    }
}

错误发生在这一行:

vector<Listener> *listeners = c.GetListeners();

错误表明

A value of type "std::vector<<error-type>, std::allocator<<error-type>>>*" cannot be used to initialize entity of type "std::vector<<Listener>, std::allocator<<Listener>>>*"

我试图研究这个错误,但没有发现任何东西表明它为什么假定返回的向量被定义为错误类型。任何帮助将不胜感激,在此先感谢。

编辑

我被告知,当我传递侦听器的地址时,它是一个局部变量,它并没有规避函数完成时对局部变量的破坏(实际上在引起我注意时非常明显谢谢大家) .不幸的是,即使我进行了调整以返回向量本身而不是其地址,我仍然收到完全相同的错误消息(当然减去指针)。我的代码现在是这样的:

vector<Listener> Component::GetListeners() {
    vector<Listener> listeners;
    for (int i = 0; i < listenerSize; i++) {
        Listener listener = { this, static_cast<EventType>(Component::listensFor[i]) };
        listeners.push_back(listener);
    }
    return listeners;
}

void Entity::AddComponent(Component c) {
    components.push_back(c);
    vector<Listener> listeners = c.GetListeners();
    for (int i = 0; i < listeners.size; i++) {
    }
}

更多代码 事件.h

struct Listener {
    Component *component;
    EventType type;
};

enum EventType {
    PhysCol = 0,
    WheelRayCol = 1,
    Accelerate = 2,
    Turn = 3,
    Fire = 4,
    Damage = 5
};

class Event {
public:
    static EventType type;
    Entity *actor;
};

组件.h

#include "Event.h"
class Component {
private:
    void Invoke(Event *e);
    //int entityID;
    Entity *entity;
    int id;
public:
    static int listensFor[0];
    //static vector<int> listensFor;
    static int listenerSize;
    static ComponentType type;
    bool enabled = true;

    //Component();
    void HandleEvent(Event *event);
    //static Component CreateComponent(ComponentType type);
    vector<Listener> GetListeners();
    int GetID();
    void RegisterEntity(Entity *e);
};

int Component::listenerSize = 0;

组件.cpp

#include "Component.h"
vector<Listener> Component::GetListeners() {
    vector<Listener> listeners;
    for (int i = 0; i < listenerSize; i++) {
        Listener listener = { this, static_cast<EventType>(Component::listensFor[i]) };
        listeners.push_back(listener);
    }
    return listeners;
}

Entity.h

#include "Event.h"
class Entity {
public:
    Transform transform;

    Component GetComponent(ComponentType type);
    void HandleEvent(Event *event);
    void AddComponent(Component component);

    int GetId();
    std::string GetTag();
    bool MatchesTag(std::string tag);
private:
    int id;
    std::string tag;
    std::vector<Component> components;
    std::vector<Listener> listeners;
};

Entity.cpp

#include "Entity.h"
void Entity::AddComponent(Component c) {
    components.push_back(c);
    vector<Listener> l = c.GetListeners();
    for (int i = 0; i < l.size; i++) {
        listeners.push_back(l[i]);
    }
}

【问题讨论】:

  • 编辑后,您发布的代码看起来不错。您能否发布一个重现错误的minimal reproducible example,或者至少是完整的错误文本?没有看到更多我的第一个猜测是循环包含或类似的东西。
  • @MilesBudnek 没问题,感谢您的关注
  • 您发布的代码不是最小的、完整的或可验证的,但我确实看到了一些可疑的事情。您将指向函数参数的指针存储在 Listener 对象中,一旦函数返回,它就会变得悬空,我不确定您试图用 static int listensFor[0]; 完成什么。我无法将您发布的代码粘贴到我的编辑器中并进行编译,因此我实际上无法重现您看到的特定错误。
  • @MilesBudnek 抱歉,这是一个大项目,所以获得最小化是相当棘手的。 static int listensFor[0] 主要是对我自己的提醒。我使用 Component 作为层次结构的基类,虽然static int listensFor[0] 不会被继承,但它提醒我为其派生类构造一个新的listensFor 数组。另一方面,它不是我收到的构建错误,而是编译前的智能感知错误。如果有帮助,我刚刚添加了 Event 和 EventType 代码,我觉得这就是编译所需要的全部
  • 这些函数都不是返回引用,而是返回指针。您可以而且应该简单地返回向量本身

标签: c++ vector return


【解决方案1】:

在 Component::GetListeners 中,您返回的是函数局部变量的地址,该变量立即超出范围并被破坏。您要么需要使其不在本地运行,要么不返回指针。

如果使用现代 c++ 编译器(c++11),则返回类型可能为“vector”和“return std::move(listeners);”并避免复制。我的理解是,更现代的 (c++17) 编译器会自动执行此操作。

【讨论】:

  • 你应该返回listeners。它将根据需要移动或删除副本。您通常不应该返回 std::move(local_variable),因为它会破坏编译器的 (N)RVO 优化并且无论如何都不需要。
  • @Sornel 哇,太棒了! a) 我不敢相信我没有注意到当地的破坏。 b) 多么棒的建议。避免复制正是我想要做的。不幸的是,无论我返回std::move(listeners) 还是只返回listeners,我仍然收到相同的错误消息,这仍然是因为本地破坏吗?因为据我所知,只要我传递对象它就不应该被破坏
  • @MilesBudnek 谢谢,我不知道的东西太多,但我正在努力学习优化
【解决方案2】:

return &amp;listeners; 返回即将被销毁的局部变量的地址——这显然很糟糕。只需按值返回您的向量。编译器很可能会忽略副本。

【讨论】:

  • 我现在自己返回listeners(不是地址),出于某种原因,我仍然收到相同的错误消息,这很奇怪,因为你所说的完全有道理
猜你喜欢
  • 1970-01-01
  • 2018-10-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-06-16
  • 1970-01-01
  • 1970-01-01
  • 2017-10-19
相关资源
最近更新 更多