在对象(而不是指针)的 std::vector 上调用 Push_back 会产生严重的副作用。那么指针会更好吗?

发布于 2024-12-01 18:20:02 字数 1058 浏览 1 评论 0 原文

这是我上一个问题的延续,我在上一个问题中提供所有信息的速度很慢,因此我创建了一个新问题,希望获得更多输入。给出:

    struct otherClass {
        ImportantObj    *ptrToImpObj;
        otherClass() {ptrToImpObj = NULL;}
    };
    struct anEntry {
        Thing *thing;
        std::vector<otherClass> *iDM2P2H;
        anEntry(Thing *tg, std::vector<sqdDMPair> *dM2Pair = NULL)
            : thing(tg), iDM2P2H(dM2Pair) {}
        ~anEntry() {delete iDM2P2H;}
    };
    std::vector<anEntry *> aQueue;
    std::vector<anEntry> bQueue;
    void aMethod () {
        Thing thingy = &(masterArrayOfThings[42]);
        aQueue.push_back(new anEntry(thingy, iDM2P2H));
    }
    void bMethod () {
        Thing thingy = &(masterArrayOfThings[42]);
        bQueue.push_back(anEntry(thingy, iDM2P2H));
    }

第二种方法将调用复制构造函数涉及的两个对象之间共享的内存上的 dtor。

在这种情况下,我觉得我应该在向量中使用指针,并且 aQueue 比 bQueue 更可取。

谢谢。

_编辑_

假设我有 20 个aQueue,它们将被清除并iDM2P2H 替换<当人工智能路线评估认为合适时,每秒数百次(数千次?)。

This follows on from my previous question, where I was slow to supply all the information so I am creating a new question in the hope of more input. Given:

    struct otherClass {
        ImportantObj    *ptrToImpObj;
        otherClass() {ptrToImpObj = NULL;}
    };
    struct anEntry {
        Thing *thing;
        std::vector<otherClass> *iDM2P2H;
        anEntry(Thing *tg, std::vector<sqdDMPair> *dM2Pair = NULL)
            : thing(tg), iDM2P2H(dM2Pair) {}
        ~anEntry() {delete iDM2P2H;}
    };
    std::vector<anEntry *> aQueue;
    std::vector<anEntry> bQueue;
    void aMethod () {
        Thing thingy = &(masterArrayOfThings[42]);
        aQueue.push_back(new anEntry(thingy, iDM2P2H));
    }
    void bMethod () {
        Thing thingy = &(masterArrayOfThings[42]);
        bQueue.push_back(anEntry(thingy, iDM2P2H));
    }

The second method will invoke the dtor on the memory shared between the two objects involved with the copy constructor.

In this case I feel I should be using pointers inside my vector and aQueue is preferable to bQueue.

Thanks.

_EDIT_

Let's say I'll have 20 aQueue's and they will be cleared and iDM2P2H replaced hundreds (thousands?) of times a second as the AI route evaluation sees fit.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

难如初 2024-12-08 18:20:02

关于删除iDM2P2H,无论是现在还是将来,您的程序都会导致该错误。如果您在两个对象中设置相同的指针,那么它们迟早都会死亡,并且它们的析构函数将尝试删除相同的内存。如果您使用指针并new对象,则当您删除anEntry对象时问题仍然存在。

解决方案很简单,避免在 anEntry 析构函数中删除 iDM2P2H,并在创建它的人的相同上下文中删除它。例如,如果它是在程序启动时创建的,那么当您完成对它的需要时,您可以在程序的主执行路径中将其删除。

About deletion of iDM2P2H, either now or ever in the future, your program is going to cause that error. If you set the same pointer in two objects, sooner or later they will both die and their destructors will try to delete the same memory. If you use pointers and new the objects, the problem persists when you delete the anEntry objects.

The solution is simply to avoid deleting iDM2P2H in the anEntry destructor, and delete it in the same context of whoever created it. That is for example if it was created at program startup, you could delete it when you have finished your need for it, in the main execution path of the program.

趁年轻赶紧闹 2024-12-08 18:20:02

您的问题是您的 anEntry 复制构造函数已损坏。默认的复制构造函数 (anEntry (const anEntry &)) 只是复制所有成员;使用类的显式析构函数,这会导致双重释放。这同样适用于默认的 operator=。根据三规则,如果您定义了以下任何一项析构函数、复制构造函数和 operator=,您通常应该实现其他两个(或者通过将它们设置为私有且未实现来禁止它们);否则其中一个的默认实现很可能会导致这样的问题。

现在,vector 类需要一个有效的复制构造函数。这是vector 合约的一部分。如果您的类缺少(即,通过将其设置为私有而禁止)复制构造函数,编译器将出错,从而防止这些“严重的副作用”。如果类有一个损坏的复制构造函数,那么,这不是vector的错。

请注意,您可能需要考虑在 anEntry 类中使用 RAII 样式的分配。例如,将 iDM2P2H 设为 std::vector 而不是 std::vector 。 *。通过这样做,您根本不需要析构函数,并且如果您可以接受默认的复制语义,则在这种情况下您可能可以使用默认的复制构造函数。

也就是说,向量的复制有时确实会带来大量开销。您可以采取多种措施来解决此问题;但是我建议反对原始的std::vector - 原因是这不会自动清理指向的元素。

相反,请使用 std::vector> (如果您有 C++0x 编译器)或 boost::ptr_vector。这将为您提供向量的自动销毁优势,但不会复制任何元素(因为向量是指向对象的指针向量)。请注意,在 unique_ptr 情况下,您需要使用std::move 将元素添加到向量中。

或者,如果您的编译器支持 C++0x 移动感知容器,您可以编写一个移动构造函数:

struct anEntry {
    Thing *thing;
    std::vector<sqdDMPair> iDM2P2H;

    anEntry(Thing *thing_, std::vector<sqdDMPair> *vec = NULL)
      : thing(thing_), iDM2P2H(vec ? *vec : std::vector<sqdDMPair>())
    { }

    // Default copy constructor and destructor OK

    // Move constructor
    anEntry(anEntry &&src)
      : thing(src.thing), iDM2P2H(std::move(src.iDM2P2H)) { }

    anEntry &operator=(anEntry &&other) {
      if (this != &other) {
        thing = other.thing;
        iDM2P2H = std::move(other.iDM2P2H);
      }
    }
};

使用 std::move 允许将 iDM2P2H 的内容移动到外部向量中的新位置无需递归复制。但是,C++0x 支持仍处于起步阶段,您的编译器和 STL 可能支持也可能不支持(如果 std::vector> 编译,你可能没问题)。

Your problem here is your anEntry copy constructor is broken. The default copy constructor (anEntry (const anEntry &)) simply copies all members; with your class's explicit destructor, this results in double freeing. The same applies for the default operator=. Per the Rule of Three, if you define any one of a destructor, copy constructor, and operator=, you should generally implement the other two (or forbid them by making them private and unimplemented); otherwise there's a good chance the default implementation of one of them will cause problems like this.

Now, the vector class requires a working copy constructor. This is part of the vector contract. If your class has a missing (ie, forbidden by making it private) copy constructor, the compiler will error out, preventing these "serious side effects". If the class has a broken copy constructor, well, that's not vector's fault.

Note that you may want to consider using RAII-style allocation in your anEntry class. For example, make iDM2P2H a std::vector<otherClass> instead of std::vector<otherClass> *. By doing so, you won't need a destructor at all, and if the default copy semantics are acceptable to you, you might be able to do with the default copy constructor in this case.

That said, vector's copying may indeed entail significant overhead at times. There are a number of things you can do to work around this; however I would recommend against a raw std::vector<anEntry *> - the reason being that this won't clean up the pointed-to elements automatically.

Instead, use a std::vector<std::unique_ptr<anEntry>> (if you have a C++0x compiler) or boost::ptr_vector<anEntry>. This will give you the automatic destruction benefits of vector but will not copy any elements (as the vector is a vector of pointers to objects). Note that in the unique_ptr case you will need to use std::move to add elements to the vector.

Alternately, if your compiler supports C++0x move-aware containers, you could write a move constructor:

struct anEntry {
    Thing *thing;
    std::vector<sqdDMPair> iDM2P2H;

    anEntry(Thing *thing_, std::vector<sqdDMPair> *vec = NULL)
      : thing(thing_), iDM2P2H(vec ? *vec : std::vector<sqdDMPair>())
    { }

    // Default copy constructor and destructor OK

    // Move constructor
    anEntry(anEntry &&src)
      : thing(src.thing), iDM2P2H(std::move(src.iDM2P2H)) { }

    anEntry &operator=(anEntry &&other) {
      if (this != &other) {
        thing = other.thing;
        iDM2P2H = std::move(other.iDM2P2H);
      }
    }
};

Using std::move allows the contents of iDM2P2H to be moved to the new position in the outer vector without copying recursively. However, C++0x support is still in its infancy, and your compiler and STL may or may not support it yet (if std::vector<std::unique_ptr<int>> compiles, you're probably ok).

紫罗兰の梦幻 2024-12-08 18:20:02

这取决于您的物体的价格和大小。如果对象很小,那么拥有一个对象向量是可以的,但如果它们很大或昂贵1,则所有复制/构造/销毁都会对性能造成很大影响,在这种情况下,您应该使用指针(然后你必须管理所有对象的内存等)。

1 如果一个类没有很多数据成员(因此它的大小不大),但它管理着在复制、销毁或创建时会发生更改的昂贵资源,那么该类可能会很小且昂贵。

It depends on how expensive and big your objects are. Having a vector of objects is ok if they're small, but if they're big or expensive1, all the copying/constructing/destructing can add up to a large performance hit, in which case you should use pointers (and then you have to manage the memory for all the objects, etc).

1 A class can be small and expensive if it doesn't have many data members (so it's not big in size) but manages expensive resources that are changed when it is copied, destroyed, or created.

风吹雨成花 2024-12-08 18:20:02

如果您确实有包含指向共享数据/资源的指针的对象,也许您可​​以考虑使用 std::shared_ptr 而不是仅仅在 delete 中调用>dtor。

使用指针的 std::vector<> 可能会让问题暂时消失,但它可能只是掩盖了共享资源管理的更基本问题。

希望这有帮助。

If you really have objects that contain pointers to shared data/resources, maybe you could consider using std::shared_ptr<my_shared_type> rather than just having delete called in the dtor.

Using std::vector<> of pointers might make the issues go away for awhile, but it's potentially just masking a more fundamental issue of shared resource management.

Hope this helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文