繁体   English   中英

需要带有O(1)擦除的std :: vector

[英]need a std::vector with O(1) erase

我很惊讶地发现vector :: erase在调用delete时移动元素。 我以为它将最后一个元素与“待删除”元素交换,并将大小减小一个。 我的第一个反应是:“让我们扩展std :: vector并重写ride()”。 但是我在许多线程中发现“ 从C ++ STL容器派生出任何真正的风险吗? ”,它可能导致内存泄漏。 但是,我没有在vector中添加任何新的数据成员。 因此,没有额外的内存可以释放。 还有风险吗?

有些人建议我们应该更喜欢组合而不是继承。 在这种情况下,我无法理解这个建议。 为什么我要浪费时间来包装包装本来不错的std :: vector类的每个函数的“机械”任务? 对于这个任务,继承确实是最有意义的-还是我错过了一些东西?

为什么不编写只执行所需功能的独立函数呢?

template<typename T>
void fast_erase(std::vector<T>& v, size_t i)
{
   v[i] = std::move(v.back());
   v.pop_back(); 
}

虽然所有归功于Seth Carnegie。 我最初使用“ std :: swap”。

微妙的问题。 您要打破的第一条准则是:“ 继承不是为了代码重用 ”。 第二个是:“不要从标准库容器继承”。

但是:如果可以保证,没有人会使用您的unordered_vector<T>作为vector<T>那么您很好。 但是,如果有人这样做,则无论您有多少成员,结果都可能是不确定的和/或可怕的(它看起来工作得很好,但仍然是不确定的行为 !)。

您可以使用private继承,但是这并不能使您摆脱编写包装程序或使用大量 using语句提取成员函数的麻烦,这几乎与组合的代码一样多(尽管少了一些)。


编辑:我的意思是using语句是这样的:

class Base {
  public:
    void dosmth();
};

class Derived : private Base {
  public:
    using Base::dosmth;
};

class Composed {
  private:
    Base base;
  public:
    void dosmth() {return base.dosmth(); }
};

您可以使用std::vector所有成员函数来执行此操作。 如您所见, Derived代码明显少于Composed代码。

在以下示例中,继承的风险:

std::vector<something> *v = new better_vector<something>();
delete v;

这将导致问题,因为您删除了没有虚拟析构函数的基类的指针。
但是,如果您总是像以下那样删除指向类的指针:

better_vector<something> *v = new better_vector<something>();
delete v;

或不将其分配到堆上就没有危险。 只是不要忘记在析构函数中调用父析构函数。

我以为它将最后一个元素与“待删除”元素交换,并将大小减小一个。

vector ::: erase在将最后一个元素移到擦除的元素时保持元素的顺序,并且不减小其大小。 由于vector实现数组,因此没有O(1)方式可以保持元素顺序并同时擦除(除非您删除最后一个元素)。

如果维护元素的顺序并不重要而不是解决方案还可以,那么最好使用其他容器(例如list ,它实现双向链接的list)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM