Существует ли стандартный контейнер для последовательности фиксированной длины, где эта длина определена во время выполнения. Предпочтительно, я хотел бы передать аргумент конструктору каждого элемента последовательности и использовать этот аргумент для инициализации члена const (или ссылки). Я также хотел бы получить элемент последовательности в заданном индексе в O (1). Мне кажется, что все мои требования не могут быть выполнены одновременно.Контейнер фиксированного динамического размера
- Я знаю, что
std::array
имеет фиксированную длину, но эта длина должна быть известна во время компиляции. std::vector
имеет динамический размер и позволяет передавать аргументы конструктора с использованиемemplace
. Хотя вы можетеreserve
памяти, чтобы избежать фактических перераспределений, тип все еще должен быть movable, чтобы теоретически разрешить такие перераспределения, которые, например, предотвращает появление членов константы.- Тогда есть
std::list
иstd::forwad_list
, которые не требуют передвижного типа, но которые по-прежнему изменяемы по размеру и будут работать довольно слабо под шаблонами произвольного доступа. Я также считаю, что могут быть значительные накладные расходы, связанные с такими списками, поскольку каждый узел списка, вероятно, будет выделен отдельно. - Как ни странно,
std::valarray
- мой лучший выбор, так как он имеет фиксированную длину и не будет автоматически изменяться. Хотя существует методresize
, ваш тип не должен быть движимым, если вы фактически не назовете этот метод. Основным недостатком здесь является отсутствие специальных аргументов конструктора, поэтому инициализация членов константы невозможна при таком подходе.
Есть ли какая-то альтернатива, которую я пропустил? Есть ли способ настроить один из стандартных контейнеров таким образом, чтобы он удовлетворял всем моим требованиям?
Edit: Чтобы дать вам более точное представление о том, что я пытаюсь сделать, увидеть этот пример:
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());
}
Итак, вы в основном хотите абсолютно непреложный контейнер? – leftaroundabout
@leftaroundabout Нет, я полагаю, он просто хочет что-то вроде вектора, который никогда не перемещает его хранилище (и это свойство должно быть * static *, то есть известно во время компиляции). –
Я знаю, что однажды сохранил типы в 'std :: vector', которые не были перемещены. Это работало до тех пор, пока я не использовал 'resize()'. Однако я не уверен, что это поведение переносимо. – cschwan