具有普通STL接口的最大大小数组,类似于boost :: array

时间:2011-03-25 08:18:55

标签: c++ boost

是否有一个类似于数组的类,它是一个类似POD的类型,带有一个数组,但在容器中提供了可变数量的项目。也就是说,我想说数组最多有10个项目,但在任何给定时刻可能包含0到10个项目。

遗憾的是,{p> boost::arraysize()修复为常量N,因此无法替代向量。特别是我希望结构的读者不要知道它是静态数组,他们可以像任何其他容器一样使用begin()end()

显然push_back()如果超出容量范围就必须通过异常。

boost中的某些内容将是首选。

注意:必须类似POD的数据类型。为清楚起见,整个类似数组的对象,包括内容(它们本身是类似POD的类型)必须是类似POD的。这是出于序列化/复制的原因(以及与序列化/复制相关的性能)。

像POD一样我的意思是:

  • 具有编译时常量大小
  • 可以安全地记忆

对于那些说无法工作不可能的人。这没有什么巧妙的。 boost::array是类似POD的类型。它只需要为当前大小添加一个额外的字段,使其成为我想要的。我正在寻找已经存在的实现(因此经过适当的测试/维护)。

6 个答案:

答案 0 :(得分:2)

问题是(可能)初始化。你如何初始化 大小,如果是POD?你如何执行不变量 size()< = max_size?

从技术上讲,定义一些东西很容易,但是否是 另一个问题是有用的还是安全的。你为什么不 只需使用boost :: array,并保持当前大小为 一个单独的变量?

- 詹姆斯坎泽

答案 1 :(得分:1)

你说“它必须是POD数据类型”。您的收藏不需要是POD吗?

如果数据类型是POD,则std::vector提供您需要的功能,许多实现将优化数据为POD的复制/移动语义。

为什么需要替换矢量?

直接回答这个问题:我怀疑在增强中存在这样一个类,因为矢量(保持大小)已经达到了目的,因此他们认为没有真正需要它。 boost::array没有不同大小和容量的概念。

如果超过你设置的容量,你可以轻松地在vector或boost :: array周围编写自己的包装类。

现在,如果你要实现它,最可能的方法是包含向量或boost数组或常规数组的类,然后实现所有函数。我会说这是直观的,但可能有一个更聪明的解决方案来重载分配器,而不是内部持有一个boost ::数组并使用它来制作矢量的“分配”。如果你的分配器用完了容量(因为它的内部数组已满),你就抛出(应该是bad_alloc)。然后,用户只需将该类用作向量,并可以调用其所有函数,但如果他们尝试将向量增加到高于其大小,则会抛出。

由于向量的性质,您的分配器不能用作释放某些对象的堆。您只需维护一个连续的缓冲区。

关于POD或接近POD的问题,向量中的实际数据保证是一个连续的缓冲区,并且在内部你的分配器使用boost :: array,因此它将是连续的。如果你想要序列化的东西,那么boost :: serialize已经可以正确地使用向量。

  

整个集合,容器和   内容,必须是单个块   固定大小的记忆:确定为   编译时

您的分配器可能如下所示:

typename< typename T, size_t SIZE >
class Allocator
{
    struct Data
    {
        size_t num_used;
        T[SIZE] data;
    } d;

public:
    // implement allocator's methods
};

实施these

答案 2 :(得分:1)

我知道的更接近的事情是llvm::SmallVector<T,N>但是它稍微复杂一点,因为它在大小超过N时使用动态分配的存储(它还会复制现有项目,因为存储是有保证的是连续的。)

我认为实现这样的容器并不困难,特别是使用boost::array作为后端。一个简单的包装器来保持尺寸并移动物品(例如从vector的代码中获取灵感)就足够了。

答案 3 :(得分:0)

POD代表普通旧数据。 “C ++中的普通旧数据结构是一个聚合类,它只包含PODS作为成员,没有用户定义的析构函数,没有用户定义的复制赋值运算符,也没有指向成员类型的非静态成员。”基本上,根据定义,任何可以在运行时调整大小的东西都不能是POD。

答案 4 :(得分:0)

另一个替代方案(如果你不能被RYO打扰)就是对数组使用boost::optional<T>,例如:

boost::array<boost::optional<int>, 10>

上述优点是您可以测试每个条目以查看它是否已设置,而不是使用某些值未初始化的状态。这应该仍然允许对象的直接memcopy(无论是堆栈还是动态分配)。

答案 5 :(得分:0)

我需要类似的东西,动机是性能,因为缓存局部性明显优于动态分配的矢量。

我为我创建了非常简单的自定义类。

#pragma once
#include <boost/array.hpp>

template<class T, class IndexType, IndexType MaximumSize>
class StaticVector : public boost::array<T, MaximumSize>
{
  IndexType count;
public:
  StaticVector() : count(0) {}
  inline void add(const T& value)
  {
    if (this->full())
      throw std::runtime_error("Can't add (size = %d)\n", MaximumSize);
    (*this)[this->count] = value;
    this->count++;
  }

  inline void addDirty()
  {
    if (this->full())
      throw std::runtime_error("Can't add, container full.");
    this->count++;
  }

  inline void remove(IndexType index)
  {
    if (this->count > 1)
      (*this)[index] = (*this)[count - 1];
    this->count--;
  }

  inline void clear() { this->count = 0; }
  inline IndexType size() const { return this->count; }
  inline bool empty() const { return this->count == 0; }
  inline bool full() const { return this->count == MaximumSize; }
  inline const T& back() const { return (*this)[this->count - 1]; }
  inline T& back() { return (*this)[this->count - 1]; }

  inline typename boost::array<T, MaximumSize>::iterator  end()       { return this->elems + count; }
  inline typename boost::array<T, MaximumSize>::const_iterator  end() const { return this->elems + count; }
  inline typename boost::array<T, MaximumSize>::const_iterator cend() const { return this->elems + count; }
};