容器固定动态大小 [英] Container of fixed dynamic size

查看:130
本文介绍了容器固定动态大小的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

有固定长度序列的标准容器,其长度在运行时确定。优选地,我想传递一个参数到每个序列元素的构造函数,并使用该参数初始化一个const成员(或引用)。我也想获得在O(1)中给定索引的序列元素。在我看来,我的所有要求不能同时满足。

Is there a standard container for a sequence of fixed length, where that length is determined at runtime. Preferrably, I'd like to pass an argument to the constructor of each sequence element, and use that argument to initialize a const member (or a reference). I'd also like to obtain the sequence element at a given index in O(1). It seems to me that all of my requirements cannot be met at the same time.


  • 我知道 std :: array 有固定长度,但是在编译时必须知道这个长度,

  • std :: vector 具有动态大小,并允许使用 emplace 。虽然您可以 保留 内存,以避免实际重新分配,类型仍然必须可移动,以在理论上允许这样的重新分配,例如

  • 然后 std: :list std :: forwad_list ,它们不需要可移动类型,但是仍然可以调整大小,并且在随机访问模式下执行得相当差。我还觉得这样的列表可能会有相当大的开销,因为每个列表节点可能会单独分配。

  • 奇怪的是, std :: valarray 是我最好的选择,因为它有一个固定的长度,自动调整大小。虽然存在 resize 方法,你的类型不必是可移动的,除非你实际调用该方法。这里的主要缺陷是缺乏自定义构造函数参数,所以使用这种方法不可能初始化const成员。

  • I know std::array has fixed length, but that length has to be known at compile-time.
  • std::vector has dynamic size, and allows passing contructor arguments using emplace. Although you can reserve memory to avoid actual reallocations, the type still has to be movable to theoretically allow such reallocations, which e.g. prevents const members.
  • Then there is std::list and std::forwad_list, which don't require a movable type, but which are still resizable and will perform rather poorly under random-access patterns. I also feel that there might be considerable overhead associated with such lists, since each list node will likely be allocated separately.
  • Strangely enough, std::valarray is my best bet so far, since it has a fixed length and won't resize automatically. Although there is a resize method, your type won't have to be movable unless you actually call that method. The main deficit here is the lack for custom constructor arguments, so initializing const members isn't possible with this approach.

替代我错过了?是否有某种方法可以调整其中一个标准容器,以满足我的所有要求?

Is there some alternative I missed? Is there some way to adjust one of the standard containers in such a way that it satisfies all of my requirements?

em> Edit:为了更准确地了解我要做什么,请参阅以下示例:

To give you a more precise idea of what I'm trying to do, see this example:

class A {
  void foo(unsigned n);
};

class B {
private:
  A* const a;
  const unsigned i;
public:
  B(A* aa) : a(aa), i(0) { }
  B(A* aa, unsigned ii) : a(aa), i(ii) { }
  B(const std::pair<A*, unsigned>& args) : B(args.first, args.second) { }
  B(const B&) = delete;
  B(B&&) = delete;
  B& operator=(const B&) = delete;
  B& operator=(B&&) = delete;
};

void A::foo(unsigned n) {
  // Solution using forward_list should be guaranteed to work
  std::forward_list<B> bs_list;
  for (unsigned i = n; i != 0; --i)
    bs_list.emplace_front(std::make_pair(this, i - 1));

  // Solution by Arne Mertz with single ctor argumen
  const std::vector<A*> ctor_args1(n, this);
  const std::vector<B> bs_vector(ctor_args1.begin(), ctor_args1.end());

  // Solution by Arne Mertz using intermediate creator objects
  std::vector<std::pair<A*, unsigned>> ctor_args2;
  ctor_args2.reserve(n);
  for (unsigned i = 0; i != n; ++i)
    ctor_args2.push_back(std::make_pair(this, i));
  const std::vector<B> bs_vector2(ctor_args2.begin(), ctor_args2.end());
}


推荐答案

理论上 vector 具有您需要的属性。正如你所指出的,如果元素是不可复制的和/或不可分配的,则不支持可能 对包含的类型执行分配,包括特别是任何序列修改(empace_back,push_back,insert等)所以要创建一个不可复制的元素的向量,你必须在向量构造过程中构造每个元素。

Theoretically vector has the properties you need. As you noted, actions that possibly do assignments to the contained type, including especially any sequence modifications (empace_back, push_back, insert etc.) are not supported if the elements are noncopyable and/or nonassignable. So to create a vector of noncopyable elements, you'd have to construct each element during vector construction.

正如Steve Jessop在他的回答中指出的,如果你首先定义向量const,你甚至不能调用这样的修改动作 - 当然元素也保持不变。

As Steve Jessop points out in his answer, if you define the vector const in the first place you won't even be able to call such modifying actions - and of course the elements remain unchanged as well.

如果我理解正确,你只有一个构造函数参数序列,而不是真正的对象序列。如果它只有一个参数,并且包含的​​类型有一个相应的构造函数,那么很简单:

If I understand correctly, you have only a sequence of constructor arguments, not the real object sequence. If it's only one argument and the contained type has a corresponding constructor, things shoule be easy:

struct C
{
  const int i_;  
  C(int i) : i_(i) {}
};

int main()
{
  const std::vector<C> theVector { 1, 2, 3, 42 };
}

如果构造函数是显式的,你必须先创建一个列表, initializer-list中的对象:

If the constructor is explicit, you have to make a list first or explicitly construct the objects in the initializer-list:

int main()
{
  auto list = { 1, 2, 3, 4 };
  const std::vector<C> theVector (std::begin(list), std::end(list));
  const std::vector<C> anotherVector { C(1), C(44) };
}

如果每个构造对象只有一个参数, :

If it's more than just one argument per constructed object, consider a intermediate creator object:

struct C
{
  const int i_;  
  C(int i, int y) : i_(i+y) {}
};

struct CCreator
{ 
  int i; int y; 
  explicit operator C() { return C(i,y); }
};

int main()
{
  const std::vector<CCreator> ctorArgs = { {1,2}, {3,42} };
  const std::vector<C> theVector { begin(ctorArgs), end(ctorArgs) };
}

这篇关于容器固定动态大小的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆