【问题标题】:C++ vector, list or array for fixed size and predefined type data用于固定大小和预定义类型数据的 C++ 向量、列表或数组
【发布时间】:2013-11-16 02:33:18
【问题描述】:

我正在尝试为新项目选择合适的数据类型以满足以下要求:

  • 非常好!时间紧迫(用于输入数据)
  • 不对容器中的数据进行随机插入或任何操作(只读并按顺序插入)
  • 大小将在编译时固定(因此不需要动态分配)
  • 数据将在某个定义的时间段(通过线程或服务)后按顺序删除,并且必须再次为新的数据提供空白空间。

例如。假设将 1,2,3,4,5,6 插入容器中。一段时间后,将删除 6 并插入 7,因此列表将是 7、1、2、3、4、5,然后 5 将被删除等...但大小必须相同。

我想知道从性能和内存的角度来看,哪种数据结构最适合我的情况。

谢谢...

编辑:顺便说一下,它与基本的 FIFO 逻辑有点不同,因为假设我们创建了 10 个元素(大小)的数据容器,但即使它还没有到达容器的末尾,也只插入了 3 个元素(大小的限制),如果经过指定的时间,它将被删除。

顺便说一句,我正在考虑使用 boost:array,但对 std:vector 和 std:deque 有点困惑。在这种情况下有什么特别的优势吗?

【问题讨论】:

  • 为了快速插入和删除,使用std::deque 并限制大小,或者只使用数组。
  • 你有什么想法,你尝试过什么?
  • 到目前为止我还没有尝试过,我只是想先确定数据结构,因为它是项目的核心,功能并不难。我正在考虑使用 boost:array 但想知道有人有更好的解决方案或类似的经验。

标签: c++ arrays performance list vector


【解决方案1】:

我们都从我们的数据结构和算法类中知道,在哪里插入和删除很可能我们应该使用某种链表。不过,我们所知道的可能是错误的。

现代内存正在以极快的速度复制大量数据(因此您不必担心复制数据)并使用缓存进行线性搜索(链表结构将有效地解决这一问题)。这两个因素结合起来很可能意味着您应该使用一个好的旧向量或 boost::array。

但不要相信我的话,here's Bjarn Stroustrup explaining it all.

【讨论】:

    【解决方案2】:

    最快的解决方案是静态分配的数组,您可以在其中使用 head/tail/count 自己处理队列;例如

    #define MAX_NUMBER_OF_ELEMENTS 10
    
    // Use statically-allocated memory
    unsigned char raw_buf[MAX_NUMBER_OF_ELEMENTS * sizeof(X)];
    X * const buf = (X *)&raw_buf[0];
    int head, tail, count;
    
    // Returns the address for a new element on the queue
    inline void *add_element_address() {
        void *p = &buf[head];
        if (++head == MAX_NUMBER_OF_ELEMENTS) head = 0;
        count++;
        return p;
    }
    
    // Removes oldest element from the queue
    inline void remove_element() {
        buf[tail].~X();
        if (++tail == MAX_NUMBER_OF_ELEMENTS) tail = 0;
        count--;
    }
    
    // Get the n-th element from the queue where 0 is the
    // last added element and count-1 is the oldest one.
    X& element(int index) {
        index = head - index - 1;
        if (index < 0) index += MAX_NUMBER_OF_ELEMENTS;
        return buf[index];
    }
    
    void add_element(... constructor arguments ...) {
        new (add_element_address()) X(... constructor arguments ...);
    }
    

    使用这种方法,缓冲区将位于内存中的固定地址(因此也释放了一个寄存器),并且对象上不需要任何类型的副本(它们是使用placement new 直接构造的)。添加、删除和索引访问操作都是O(1)

    【讨论】:

      【解决方案3】:

      你需要有一些固定容量的 std::vector 支持的 std::queue:

      std::vector<YourType> underlying_storage(capacity);
      std::queue<YourType, std::vector<YourType>> queue(std::move(underlying_storage));
      
      // Now your queue is backed up by vector with predefined capacity
      

      【讨论】:

        【解决方案4】:

        你需要的是一个建立在固定大小数组上的循环缓冲区,这是非常简单和最快的数据结构。

        您可以编写自己的循环缓冲区类或尝试使用循环缓冲区的boost实现http://www.boost.org/doc/libs/1_54_0/libs/circular_buffer/doc/circular_buffer.html

        【讨论】:

        • hm,环形缓冲区将是一个很好的解决方案,据我所知,它与 boost:array 或 std:vector 具有相同的迭代功能。但只有我的问题的区别是;没有新数据会取代旧数据。即使经过了预先指定的时间,数据也会被删除,换句话说,当数据超时时,数据将可用于客户端应用程序。那么我真的需要一个圆形结构吗?
        • 举个例子:1,2,3,4,5,6 你删除 6 并在开头插入 7 - 没有新数据替换旧数据,但现在第一个元素不同,改变恒定时间标准数组中的第一个元素是不够的
        • 所以如果我们删除第一个输入的(最旧的)迭代器“开始”会发生变化(在我们的前它的 6 中(我们没有替换 6,因为我们仍然可以说还有 10 个空白空间) )在两个容器(标准数组和循环缓冲区)中对吗?我的意思是,如果这就是为什么标准数组还不够的情况,那么循环缓冲区的优势是什么,我的意思是有什么区别?如果我的问题听起来很愚蠢,我很抱歉,我只是想弄清楚循环缓冲区是否对这种情况有优势。感谢您的帮助...
        • 告诉我如何将这些项目放入数组中,是吗? [, , , , ..., 1,2,3,4,5,6] 然后 [, , , , ..., 7, 1,2,3,4,5, ]
        • 是的,很可能是您编写的方式。但问题是我们必须有可能在不丢失插入顺序的情况下使用最后一个空白位置(删除后 6 的位置)。可以在循环缓冲区中吗?在我们的例子中,插入顺序再次非常重要。
        【解决方案5】:

        看起来您需要一个queue,可能由一些支持 FIFO 的优化的固定大小容器支持。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-02-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多