Стандартный список C++ и типы, создаваемые по умолчанию

StackOverflow https://stackoverflow.com/questions/695372

Вопрос

Почему это конструктор с одним параметром std::list<T> требует T быть конструируемым по умолчанию типом?Я имею в виду, что следующий код не компилируется.

struct Foo { // does not have default constructor.
  Foo (int i) {} 
}
int main(void) {
  std::list<Foo> l(10);
}

Представляется возможным использовать создавать и разрушать идиомы как они уже сделали в std::vector, хотя и с большей бухгалтерией в классе списка.

Кстати, почему бы не включить функцию емкости в список?Вы можете утверждать, что такая функция заранее оплатит затраты на выделение памяти и устранит накладные расходы позже, когда вы push_back объекты.По крайней мере, это сделает интерфейсы двух контейнеров последовательностей STL немного более согласованными.

Это было полезно?

Решение

std::list не имеет функции емкости, потому что это не имеет смысла;ему никогда не придется изменять размер, как это делает вектор.Его емкость ограничена только доступной памятью, которую нелегко определить.

Судя по тому, что вы просили, я думаю, вам действительно нужен резерв().Это уникальный случай для Vector, потому что ему (очень) нужна такая вещь;нет особого требования обеспечивать согласованность всех функций во всех контейнерах STL, особенно когда они не имеют особого смысла для других.

Вы можете добиться того же эффекта, используя собственный распределитель.Как предложил Мануэль, посмотрите на наддув.

Другие советы

Не существует общего требования, чтобы тип был конструируемым по умолчанию — он должен быть копируемым и назначаемым.Ваш код не работает, потому что вы пытаетесь создать список из 10 элементов - их нужно каким-то образом сконструировать, поэтому необходимо использовать конструктор по умолчанию - но только в этом конкретном случае.Если бы вы создали пустой список и добавили в него данные, такого требования не было бы.

То же самое справедливо и для других контейнеров — попробуйте скомпилировать следующее:

#include <vector>

struct A {
    A( int x ) : z(x) {}
    int z;
};

std::vector <A> a(10);

Что касается второй части вашего вопроса, я бы просто заметил, что согласованность интерфейса не была основным критерием проектирования стандартных контейнеров - например, нет намерения, чтобы один тип контейнера был "встраиваемой" заменой для другой.Это хорошо обсуждается в пунктах 1 и 2 книги Скотта Мейерса «Эффективный STL».

Нил уже ответил на главный вопрос.

Также обратите внимание, что при вызове resize() вам понадобится конструктор по умолчанию.

Вы можете обойти это, имея список указателей на объекты в формате STL, но я думаю, это уже было для вас очевидно.

На соответствующем примечании, почему бы не иметь функцию емкости в списке?Вы можете утверждать, что такая функция будет платить затраты на распределение памяти в преддверии и устранить накладные расходы в дальнейшем, когда вы push_back объекты.По крайней мере, это сделает интерфейсы двух контейнеров STL -последовательности немного более последовательными.

Я думаю, проблема здесь в том, что Списки STL позволяют объединять перекрестные списки..Если вы хотите заранее выделить память, посмотрите Распределитель пула повышения.

Причина в том, что когда вы создаете список из n элементов (где n — параметр, который вы использовали в конструкторе), список заполняет свою структуру из n элементов копиями T().

Видеть документация SGI STL для списка.

Почему это единственный конструктор параметров STD :: требует, чтобы T был типом по умолчанию?

Потому что этот конструктор - создает список с элементами (число, которое вы передаете как параметр).Значение каждого элемента будет по умолчанию.Также вы можете использовать конструктор с двумя параметрами для создания списка с элементами, которые будут инициализированы значением второго элемента.

На соответствующем примечании, почему бы не иметь функцию емкости в списке?

Это не имеет смысла, поскольку стоимость добавления новых элементов в список намного меньше, чем в случае с вектором.

std :: vector не имеет такого ограничения.Мой вопрос: почему бы не использовать те же методы (создать/уничтожить идиомы) в списке STD :: также?

Это не ограничение.Потому что, если вы не используете такой конструктор, инициализатор по умолчанию не потребуется.То же самое верно и для вектора.

Итак, на самом деле ваш вопрос: «Почему бы не включить в список функции резерва и мощности?»

Ответ на этот вопрос заключается в том, что нет причин заранее резервировать память для списка - добавление новых элементов никогда не требует перераспределения и копирования существующих элементов, нет требования, чтобы память, содержащая содержимое списка, была непрерывной, а итераторы этого не делают. стать недействительным при выполнении list::push_back().

Все это является причиной существования vector<>::reserve(), а наличие резервной памяти для новых элементов — вот почему vector<> выполню размещение new в сырую память.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top