2012-04-26 5 views
2

Как std::vector выделить объекты? Казалось бы, он просто использует std::allocator::allocate для создания блока памяти, но затем никогда не звонит std::allocate::construct. Это правда? std::vector распределяет память и никогда не создает объекты в качестве распределения памяти?Как std :: vector выделяет объекты?

Что делать, если конструктор по умолчанию отсутствует? Как вызван конструктор, когда на объекте нет конструктора по умолчанию? Что делать, если имеется более одного параметра?

Например, с помощью этого кода нет конструктора по умолчанию, и std :: allocator разрешает его.

#include <vector> 
using namespace std; 

class A{ 
protected: 
    int m; 
public: 
    explicit A(int a) : m(a) { } 
}; 

int main(){ 
    vector<A> test; 
    return 0; 
} 
+0

@ Prætorian: Не могли бы вы предоставить источник этого?Код, который я только что поставил на вопрос, показывает, что он будет компилироваться в VS2010, и я считаю, что он также компилируется в gcc. – chadb

+0

Он цитируется из стандарта C++ 11 – Praetorian

+0

@ Prætorian: Это новое правило C++ 11 или оно было на C++ 03? – chadb

ответ

8

Это изменилось с тех пор, как C++ 11.

В C++ 03, construct может выполнять только копирование на месте.

Обратите внимание, что в частности std::vector - это массив объектов, но есть четкий размер и емкость. То есть может быть больше пустых элементов за пределами части массива, содержащей полезные данные.

Поэтому распределитель стандартной библиотеки имеет разделение между «строительство» и «распределение памяти». allocator делает оба, но не в то же время. Это позволяет std::vector выделить больше памяти, чем она использует. Когда вы добавляете новые элементы, необязательно выделять больше памяти; он может просто использовать запасную память, которую он оставил, по телефону allocator::construct.

Также обратите внимание, что все функции C++ 03, которые добавляют элементы в std::vector, принимают в качестве параметра элемент. push_back, insert, даже sized constructor takes as a value as an argument. Да, это параметр по умолчанию, но он по-прежнему принимает значение как элемент. Этот элемент скопировал в вектор, используя вызов метода construct распределителя, который берет копию.

В C++ 11 для использования функции allocator_traits<>::construct необходимы стандартные контейнеры. Это функция varadic, которая переводит свои параметры в фактическую конструкцию. Эта функция свойств (по умолчанию может быть специализированной) вызывает метод allocator::construct, если этот вызов корректно сформирован. Если нет, он попытается разместить new.

Это позволяет использовать новые функции emplace.

Но да, объекты, содержащиеся в стандартных библиотечных контейнерах, являются фактически построенными объектами. Даже если метод распределителя construct не вызывается.

0

Это зависит от реализации, но типичная реализация использует std::allocator::allocate выделить блок памяти, а затем использует размещение нового построения, с помощью конструктора копирования (или перемещения конструктора в C++ 11), экземпляры ,

Когда элементы стираются, их деструкторы вызываются непосредственно для уничтожения объектов, даже если основная память не освобождена.

+1

Копирование и перемещение конструкторов не имеют ничего общего с размещением нового. –

+0

Что делать, если конструктор по умолчанию отсутствует? Как вызван конструктор, когда на объекте нет конструктора по умолчанию? Что делать, если имеется более одного параметра? – chadb

+0

@Nicol: Я ссылался на то, что 'std :: vector' имеет тенденцию использовать конструкторы копирования (или перемещения) рассматриваемого класса во время своих строительных операторов. Поскольку размещение new по-прежнему вызывает конструктор (как и без размещения нового), это было моим намерением –

Смежные вопросы