Стандартный список C ++ и конструируемые по умолчанию типы - PullRequest
0 голосов
/ 30 марта 2009

Почему для конструктора с одним параметром 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 немного более согласованными.

Ответы [ 6 ]

5 голосов
/ 30 марта 2009

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

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

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

4 голосов
/ 30 марта 2009

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

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

#include <vector>

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

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

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

3 голосов
/ 30 марта 2009

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

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

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

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

Полагаю, проблема здесь в том, что списки STL допускают слияние между списками . Если вы хотите выделить память заранее, взгляните на Boost Pool Allocator .

2 голосов
/ 30 марта 2009

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

См. Список документации sgi stl .

0 голосов
/ 30 марта 2009

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

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

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

0 голосов
/ 30 марта 2009

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

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

На связанной ноте, почему бы не иметь Емкость функции в списке?

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

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

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

...