【问题标题】:stl vector vs arraystl 向量与数组
【发布时间】:2010-12-03 23:19:01
【问题描述】:

正如answer 到我的question 中所述,我将使用向量来调整大小为 N,读取和写入 n

附:很少需要调整大小和块复制。

编辑: 正如 David Rodríguez - dribeas 所要求的,这是一个技术分析程序。历史股票价格保存为向量中的 OHLC 条。所以我真的需要将元素存储在向量中。还有一些其他的计算类称为指标,根据股票价格进行计算。当一个新的价格通过 tcp 到达时,股票首先更新它的 bar 并立即调用它所有相关指标的计算方法,说,“好吧,伙计们,我的第 n 条 bar 已经在这个特定的时间更新了。你自己去计算吧。”所有操作都是基于任务的,也就是说,在完成最后一次更新之前,股票永远不会自我更新,同样,当最后一次更新正在进行时,指标永远不会进行计算。一次一项任务。如果新的更新来得太快,它们可以被缓存为任务。因此,股票可以等待其最后一次更新完成,并且指标可以在计算时类似地存储其任务,但股票不能等待其指标完成其工作。这就是问题的开始。如果更新到达,股票首先查看其条形矢量大小并检查是否必须调整大小。如果需要,它会调整其向量的大小,而在上一次更新之前可能有一些指标仍在工作。指标可能会到达其股票数据,因为数据可能会被调整大小。到目前为止,我没有任何问题,因为指标计算已经非常非常快地完成了。但我很担心。作为一种解决方案,股票可以生成第二个更大的条形向量,并告诉其指标它们可以到达第二个向量以进行后续计算。最终,几秒钟后,对第一个向量的所有访问都消失了,它可以被逐渐删除。

【问题讨论】:

  • 正如我在 cmets 中对我的回答所解释的那样,您不能将元素从一个线程插入向量并从另一个线程中的同一向量读取元素。向量重新分配不是唯一的问题;向量执行的内部簿记也是一个问题,您不能对其中涉及的内容做出任何假设。一旦您向消费者线程授予对向量的访问权限,您就不能再次修改它,除非(a)您同步对它的访问,您说过您不想这样做,或者(b)您让所有消费者停止访问向量,这可能很困难。
  • 为了在多线程环境中获得最佳性能,您可能需要考虑实现自己的容器。
  • @James McNellis:内部簿记是什么意思?
  • @Bahadir Turkmen:向量必须以某种方式跟踪其大小和容量。有两种典型的实现方式:一种使用存储大小和容量的两个整数;另一种使用存储大小和容量的整数。另一个使用两个指针,一个指向当前数据末尾的元素(指示大小),另一个指向基础数组末尾的元素(指示容量)。任何插入向量都会修改大小。大小也可以被vector的任何成员函数读取,包括operator[]
  • @James McNellis:我明白了,所以我需要一个在到达元素时不检查其大小的容器。我还保证自己所需的索引在 [0,n] 的范围内。所以我根本不需要使用向量。我可以很容易地设计一个数组来抓取它的元素,即使是多线程的情况。你这么认为吗?

标签: c++ arrays stl vector


【解决方案1】:

听起来你真正想要的结构是std::deque,它可以在摊销的常数时间内附加。

实际上,调整大小的策略正是std::vector 已经使用的策略。事实上,它使用的精确策略意味着这个操作本质上是 O(1),但只是在很长一段时间内的许多附加方面。无论如何,似乎没有任何理由重新发明轮子。只需使用std::vector.push_back()std::queue.push_back()

【讨论】:

  • operator[] of std::dequestd::vector 慢。由于在我的应用程序中确实经常使用读写操作,我不想失去性能。也说了,多线程场景中可能会涉及到一些危险的情况,用deque。
  • 附加到std::deque 的成本是常数时间,而附加到std::vector 的成本是摊销常数时间。
【解决方案2】:
  1. 为什么不调整现有的大小 矢量?
  2. 如果您无法调整现有向量的大小,那么您可以使用数组来实现,我看不出在这种情况下使用std:vector 有什么好处,对于复制,您可以使用memcopy
  3. 您可以使用数组并使用realloc 调整她的大小。

【讨论】:

  • 因为当一个线程正在调整向量的大小时,另一个消费者线程可能会到达该向量。
  • 这取决于你想在容器中存储什么,但一般来说,你不能将 memcpy 用于非 POD 类型的任何东西——任何具有非平凡构造函数或析构函数的东西。跨度>
  • @David Rodríguez - dribeas:我将只存储数字类型。
  • @David Rodríguez:您没有权利,您将对象视为数组的一些长度数据,但不是真的,不完全是,为了访问她,您只有指向该对象开始位置的指针,和她一起你想做你想做的事,没有人给你复制对象的命令,只复制她的起始地址(这是你可以在谷歌上读到的关于她的指针)。
  • 无论如何,您也可以将memcpy 与向量一起使用(可能比std::copy 性能稍好:std::vector<int> a; /* ... */ std::vector<int> b( 2*a.size() ); memcpy( &b[0], &a[0], a.size()*sizeof a[0] );
【解决方案3】:

我阅读了最初的问题,我认为处理多线程可能是值得的,这样你就可以保证在你增长容器时没有线程会访问容器。

在手头的特定问题上,除非有充分的理由不这样做,否则我总是会在数组上使用std::vector,如果没有其他原因只是因为已经实现了许多操作而您没有需要手动管理内存。

无论如何,你在这两个问题中都没有提供很多信息,比如使用模式是什么,消费者线程对数据做了什么(你真的需要将元素保留在向量中吗?线程可以选择一组值并使用它吗?),有哪些同步机制(消费者如何收到容器中有额外数据的通知,额外数据何时到达..)所有这些问题以及他们的回答可能会为其他设计提供提示。

【讨论】:

    【解决方案4】:

    我想说,在您的情况下,最坏的情况是,向​​量不会比动态分配的原始数组好。可能会更方便。

    至于你的困境,这听起来像是隐式内存管理更容易的事情。您可以将传入的数据存储在共享指针中。然后,指标在开始计算时获取指向所需数据的共享指针。如果新数据进入需要使旧数据失效,只需将包含旧数据的股票中的共享指针替换为包含新数据的共享指针。任何仍在使用旧数据的指标都可以继续使用它,因为它仍然有一个指向旧数据的共享指针(防止旧数据被清理),并且当所有使用该数据的指标完成时旧数据将被清理并且重置它们的共享指针。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-10-10
      • 2011-09-11
      • 1970-01-01
      • 2011-02-13
      • 2011-01-08
      • 2021-10-22
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多