【问题标题】:fast way to delete entries of STL vector of pointers删除 STL 指针向量条目的快速方法
【发布时间】:2013-11-23 16:44:03
【问题描述】:

我有一个要删除的指针向量,但是遍历该向量并为每个元素调用delete 非常慢。有更快的方法吗?

不幸的是,我确实需要存储指针,因为我使用的是虚拟超类。简化后,类结构如下所示:

class VirtualSuperClass
{
protected:
    SomeType m_someMember;
    // ...
public:
    virtual void doSomething() = 0;
};

class Subclass_1 : public VirtualSuperClass
{
protected:
    SomeType m_someSubclassMember;
    // ...
public:
    virtual void doSomething() { /* do something*/ }
};

class Subclass_2 : public VirtualSuperClass
{
protected:
    SomeType m_someOtherSubclassMember;
    // ...
public:
    virtual void doSomething() { /* do something else*/ }
}

在我的 main 方法中,我填充超类的指针向量,并为每个元素调用函数 doSomething()

int main()
{
    std::vector<VirtualSuperClass*> vec;
    vec.push_back(new Subclass_1());
    vec.push_back(new Subclass_2());
    vec.push_back(new Subclass_2());
    vec.push_back(new Subclass_1());
    // and so on, about 40,000 elements (not really done with .push_back :) ) ...

    // this actually runs in an application loop
    for (size_t i = 0; i < vec.size(); i++)
    {
        vec[i]->doSomething();
    }

    // ...

    for (size_t i = 0; i < vec.size(); i++)
    {
        delete vec[i];     // <-- pretty slow for large number of elements
        vec[i] = NULL;
    }
    vec.clear();
    return 0;
}

【问题讨论】:

  • 如果你存储 shared_ptr&lt;VirtualSuperClass&gt; 而不是指针,那么编译器会为你处理这个问题。
  • @JonathanPotter:但是速度不会慢,我认为这就是问题所在。
  • 如果你的向量在下一行超出范围,那么在delete 之后调用clear() 并设置指向NULL 的指针是没有意义的。只需执行deletes(或使用智能指针,不要)并返回。

标签: c++ pointers vector stl stdvector


【解决方案1】:

您可能正在寻找一个用于您分配的类的自定义分配器 - 这样您可以有效地批量获取和释放系统内存,而不是以小片段的形式 - 这可能是提高“整体”性能的唯一解决方案这个系统的性能而不修改它(考虑到你的瓶颈肯定看起来是个好主意;))。

【讨论】:

  • 假设析构函数中没有复杂的任务,真正的瓶颈是释放。
  • 正确并考虑到我们拥有的数据,我认为是这种情况(即删除线指出的瓶颈不是析构函数体之一等)
  • @RnR:编写分配器是我以前从未做过的事情,但听起来很有趣。我会试试看。
  • @RnR 实际上我有点卡在这里。当我为向量中的指针编写自定义分配器时,我能够控制指针的分配方式,但这如何帮助我在单个数据块中分配实际对象?还是我理解您的解决方案有误?我也尝试过重载“新”运算符,但是我遇到的问题是,当我的内存块变得太小时,我必须重新分配它,并且所有旧指针都必须更新:(
  • 是的——编写自定义分配器并不容易。关键是你需要有一个新的,从一些更大的数据块中删除适当数量的内存,然后你需要考虑管理这些更大的块等。我用谷歌搜索了一下,发现我们有一些似乎可以解决的问题boost中的这个问题-也许您可以尝试一下? boost.org/doc/libs/1_41_0/libs/pool/doc/index.html
【解决方案2】:

任何正确解决方案都归结为在每个指针上执行delete。既然您已经分析了您的代码并将其确定为瓶颈,那么我会寻找一种将delete 移动到另一个线程的解决方案。

这可以通过以下方式完成:

  1. 创建一个工作线程,deletes 指针传入
  2. 从向量中移除指针并将它们复制到工作线程拥有的另一个向量中
  3. 启动工作线程作业,让它删除指针

就纯 CPU 时间而言,这不会比您当前的解决方案更快(实际上可能会更慢,具体取决于您的操作方式),但它会将繁重的工作从主线程中移出。

【讨论】:

  • 如果你要走这条路,那么为什么还要复制而不是将矢量内容交换/移动到另一个线程中呢?
  • @Nobody:当然,这似乎很合理。但是,您必须确保要移动到的向量已锁定。
  • @JohnDibling:当我仍然想使用我的程序时删除内存时,这种方法可以工作。但它不会减少程序最终清理所需的时间,我需要它。根据我当前的实现,停止程序大约需要五分钟。
  • @maddin45:你没有从我这里听到,但如果你根本不这样做delete,它将在 linux 和 windows 下的应用程序关闭时回收。
  • @JohnDibling:这可能会有所帮助,但是我们的教授让我们使用一个工具来检查内存泄漏,这将是一个很大的泄漏;)
【解决方案3】:

可能提高性能的另一种方法是使用一种内存池,您可以在其中预先分配一个大的原始缓冲区,然后在该缓冲区中放置-new 每个单独的对象。

这具有提高性能的潜力,因为尽管您仍然必须销毁每个指针,但该销毁是通过直接调用析构函数而不是deleteing 来完成的。这避免了使用系统的内存管理器,而这种避免是提高性能的潜力所在。

但是,这种方法有一些重要的警告,除了最极端的情况外,我不会推荐它。需要注意的是,你要自己承担管理自己记忆的繁重责任。

【讨论】:

  • 我想过这个问题,但这需要我重构我的大部分代码。
猜你喜欢
  • 2021-06-14
  • 1970-01-01
  • 1970-01-01
  • 2013-09-24
  • 2012-08-12
  • 2015-08-09
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多