gpt4 book ai didi

c++ - 固定动态大小的容器

转载 作者:IT老高 更新时间:2023-10-28 12:48:55 26 4
gpt4 key购买 nike

是否有用于固定长度序列的标准容器,其中该长度在运行时确定。最好,我想将一个参数传递给每个序列元素的构造函数,并使用该参数来初始化一个 const 成员(或引用)。我还想在 O(1) 中的给定索引处获取序列元素。在我看来,我的所有要求都无法同时满足。

  • 我知道std::array具有固定长度,但必须在编译时知道该长度。
  • std::vector具有动态大小,并允许使用 emplace 传递构造函数参数.虽然可以reserve内存以避免实际的重新分配,类型仍然必须是 movable理论上允许这样的重新分配,例如阻止 const 成员。
  • 然后是std::liststd::forward_list ,它不需要可移动类型,但仍然可以调整大小,并且在随机访问模式下表现相当差。我也觉得这样的列表可能会有相当大的开销,因为每个列表节点可能会被单独分配。
  • 奇怪的是,std::valarray到目前为止是我最好的选择,因为它有固定的长度并且不会自动调整大小。虽然有一个resize方法,除非您实际调用该方法,否则您的类型不必是可移动的。这里的主要缺陷是缺少自定义构造函数参数,因此无法使用这种方法初始化 const 成员。

我错过了一些替代方案吗?有什么方法可以调整其中一个标准容器以满足我的所有要求吗?


编辑:为了让您更准确地了解我正在尝试做什么,请参阅以下示例:

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、插入等)。因此,要创建不可复制元素的 vector ,您必须在 vector 构造期间构造每个元素。

正如 Steve Jessop 在他的回答中指出的那样,如果您首先定义 vector const,您甚至无法调用此类修改操作 - 当然元素也保持不变。

如果我理解正确,您只有一个构造函数参数序列,而不是真正的对象序列。如果它只有一个参数并且包含的​​类型有相应的构造函数,事情应该很容易:

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

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

如果构造函数是显式的,则必须先创建一个列表或显式构造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) };
}

如果每个构造对象不止一个参数,请考虑使用中间创建者对象:

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) };
}

关于c++ - 固定动态大小的容器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14895052/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com