C++ C++;向量、列表、指针和混淆

C++ C++;向量、列表、指针和混淆,c++,pointers,data-structures,C++,Pointers,Data Structures,我有一个实体类,其中包含用于特定类型实体的各种子类。子类的对象彼此之间有各种关系,因此我使用实体指针和静态类型转换来描述这些关系,并允许实体访问与它们有关系的其他实体的信息 然而,我发现使用原始指针会带来很多困难&难以调试错误。例如,在将对象复制到向量之前,我浪费了几个小时才意识到我在创建指向对象的指针,这会使指针无效 我正在使用向量和列表以及类似的stl容器来管理我所有的内存——我真的试图避免担心内存管理和低级问题 说Cow是实体的子类,我有一个奶牛的向量(或者奶牛的一些数据结构)。如果这个向

我有一个实体类,其中包含用于特定类型实体的各种子类。子类的对象彼此之间有各种关系,因此我使用实体指针和静态类型转换来描述这些关系,并允许实体访问与它们有关系的其他实体的信息

然而,我发现使用原始指针会带来很多困难&难以调试错误。例如,在将对象复制到向量之前,我浪费了几个小时才意识到我在创建指向对象的指针,这会使指针无效

我正在使用向量和列表以及类似的stl容器来管理我所有的内存——我真的试图避免担心内存管理和低级问题

说Cow是实体的子类,我有一个奶牛的向量(或者奶牛的一些数据结构)。如果这个向量需要调整大小或其他什么,它可能会在内存中移动。我真的不想关心这些细节,但我知道它们可能会使我的指针失效。因此,如果一头猪与一头母牛有关系,并且母牛向量的大小被调整,那么猪就失去了它的朋友在内存中的位置&有一个危险的错误指针

这里是我的问题,虽然我认为有经验的人可能会通过阅读情况来帮助我

  • 我是否应该尝试在实体对象的构造函数/析构函数中插入一些内容,以便它们在被删除时自动使其他实体与它们的关系无效,或者在移动时更新内存位置?如果这是一个好方法,那么语义方面的任何帮助都会很有用。我写的所有类都没有构造函数或析构函数,所以它们非常容易在向量之类的东西中使用
  • 如果我知道容器将要移动,那么跟踪容器并手动更新指针是更好的选择吗?因此,这里的策略是迭代任何可能在移动之后立即移动的容器,并立即更新所有指针

  • 据我所知,你在做这样的事情:

    cow florence, buttercup;
    std::vector<cow> v = { florence, buttercup };
    cow* buttercup_ptr = &v[1];
    
    // do something involving the cow*
    
    std::shared_ptr<cow> florence = std::make_shared<cow>();
    std::vector<std::shared_ptr<cow>> v;
    v.push_back(florence);
    
    您现在可以自由共享
    florence
    。。。如果不考虑向量的移动方式,它仍然有效

    如果你想在你把florence从向量中弹出时让她被销毁,这就带来了一个小问题:任何人持有共享的ptr副本都会阻止清理这个特定的
    cow
    实例。您可以通过使用
    弱\u ptr
    来避免这种情况

    std::weak_ptr<cow> florence_ref = florence;
    

    我不认为我一定会建议这个选择,尽管我相信它会奏效。使用智能指针是一种更好的方式来向未来的维护程序员展示您的意图,其优点是获取悬空引用要困难得多。

    您对指针有误解。指针(为了便于讨论!)只是一个地址。为什么复制地址会使任何东西无效?假设您的对象是在内存中的地址
    12345
    创建的<因此,code>new将为您提供一个值为
    12345
    的指针:

    Entity *entity = new Cow; // object created at address 12345
    // entity now has value 12345
    
    稍后,当您将该指针复制到向量(或任何其他标准容器)中时,只复制值
    12345

    std::vector<Entity *> entities;
    entities.push_back(entity);
    // entities[0] now has value 12345, entity does not change and remains 12345
    

    如何解决这个问题是在C++中的成千上万个问题,网站,博客和书籍的主题。智能指针可能对您有所帮助,但您应该首先真正理解所有权的概念。

    我的两分钱。下面的代码是一个使用智能指针和工厂函数
    create
    的工作示例(C++11,用g++4.8.2翻译)。应该是完全安全的。(如果你真的想,你可以在C++中破坏某些东西)
    #包括
    #包括
    
    #include允许构造函数在派生类中具有任意数量的参数。在程序的修改版本中,将母牛的产奶量作为构造函数参数传递给新创建的母牛。

    您可能有兴趣阅读此内容:问题的作者与您或多或少的陈述有相同的误解。我将阅读此内容。仅仅看了10秒钟,我想我应该说我没有使用指针向量。我一直在声明对象并将它们复制到向量中&让向量管理内存。我真的,真的想避免手动新建和删除东西,这就是我这样做的原因。如果可能的话,也许我想要的是像唯一指针的向量一样的东西?让指针进入变化的容器似乎是一件奇怪的事情。也许你可以考虑一个容器,其中插入和删除不会使迭代器无效(<代码> map < /COD>,<代码> SET,和列表这可能是正确的),并使用迭代器来跟踪你的对象。我一直在使用向量,因为我经常需要遍历对象并调用各种更新函数。我了解到,由于缓存问题,遍历列表或集合的速度会慢一些。@user3281410除了Rook的解释之外,存储使用智能指针管理的对象实例,听起来更适合您的情况。+1用于提及使用智能指针的管理。我相信这将至少为OP的用例提供最合适的解决方案。@Rook我仍在处理您编写的内容。我正在输入一个问题,当我从矢量中删除一头牛时会发生什么,然后我刷新了页面,你已经编辑了你的帖子,精神上的lol。谢谢你的帮助@ChristianHackl阅读了我对这个问题的其他评论,并查看了我给出的链接。智能指针的使用不会影响任何东西,在这个用例中是非常值得推荐的
    std::vector<Entity *> entities;
    entities.push_back(entity);
    // entities[0] now has value 12345, entity does not change and remains 12345
    
    int i = 12345;
    std::vector<int> ints;
    ints.push_back(i);
    // ints[0] now has value 12345, i does not change and remains 12345
    
    std::vector<int> ints2 = ints;
    std::vector<Entity *> entities2 = entities;
    // i, ints[0] and ints[0] are 12345
    // entity, entities[0] and entities[0] are 12345
    
    delete entity;
    entities[0]->doSometing(); // undefined behaviour, may crash