Как контейнеры STL копируют объекты?
Я знаю, что контейнеры STL, такие как vector
, копируют объект при его добавлении. push_back
метод выглядит следующим образом:
void push_back ( const T& x );
Я удивлен, увидев, что этот предмет занимает позицию. Я написал пример программы, чтобы увидеть, как она работает.
struct Foo
{
Foo()
{
std::cout << "Inside Foo constructor" << std::endl;
}
Foo(const Foo& f)
{
std::cout << "inside copy constructor" << std::endl;
}
};
Foo f;
std::vector<Foo> foos;
foos.push_back(f);
Это копирует объект, и я вижу, что он вызывает экземпляр-конструктор.
Мой вопрос: когда push_back
принимает элемент в качестве ссылки, как он вызывает экземпляр-конструктор? Или я здесь что-то не хватает?
Любые мысли..?
Ответы
Ответ 1
Вероятно, он использует "размещение new
" для построения объекта в своем внутреннем массиве. Размещение new
не выделяет никакой памяти; он просто помещает объект, который вы укажете, и вызывает конструктор. Синтаксис new (address) Class(constructor_arguments)
.
Конструктор копирования T::T(T const &)
вызывается для создания копии на месте. Что-то вроде этого (упрощенного):
template<T>
void vector<T>::push_back(T const &item) {
// resize if necessary
new (&d_array[d_size++]) T(item);
}
Обратите внимание, что для T
должен быть создан конструктор копирования. По умолчанию (если вы ничего не делаете), он получает один бесплатно. Если вы определяете его явно, для работы vector<T>
должно быть public
.
Вот как это делает GNU libstdС++, но я сомневаюсь, что это будет очень полезно. Существует распределитель (второй аргумент шаблона vector
), который делает его менее простым.
Ответ 2
С++ SDK всегда использует const T &
как функциональный параметр для эффективности.
В вашем случае, если в качестве параметра требуется T
, действие копирования будет выполняться дважды, одно для передачи его функции push_back(f)
, одно для внутреннего добавления в контейнер. И, беря const T&
в качестве параметра, требуется только одна копия!
Ответ 3
Он использует новый оператор размещения и копирует его в унифицированную память;
Размещение new создает новый элемент с указанным адресом в памяти, в векторном случае, текущий конец();
void push_back(const T& val){
::new (&*end()) T(val);
[increase end]
}
посмотрите http://spotep.com/dev/devector.h, который имеет совершенно четкий код (в отличие от большинства реализаций STL).