Как контейнеры 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);

Это копирует объект, и я вижу, что он вызывает copy-constructor.

Мой вопрос: когда push_back берет элемент в качестве ссылки, как он вызывает конструктор-копию? Или я что-то здесь упускаю?

Какие-нибудь мысли..?


person Navaneeth K N    schedule 07.11.2009    source источник


Ответы (3)


Вероятно, он использует «размещение 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 должен иметь конструктор копирования, чтобы это работало. По умолчанию (если вы ничего не делаете) он получает один бесплатно. Если вы определяете его явно, он должен быть public, чтобы vector<T> работало.

Вот как это делает GNU libstdc++, но я сомневаюсь, что это будет очень поучительно. Существует распределитель (второй аргумент шаблона для vector), который делает его менее простым.

person Thomas    schedule 07.11.2009
comment
Это нормально, когда T имеет конструктор без параметров. Но что произойдет, если у него будет параметризованный конструктор? Как вектор может инициализировать новый объект? - person Navaneeth K N; 07.11.2009
comment
Это нормально, когда T имеет конструктор копирования. Что есть по умолчанию, и если вы его реализуете, если вы явно не сделали его private или protected. - person Thomas; 07.11.2009
comment
Спасибо. Я буду исследовать дальше. - person Navaneeth K N; 07.11.2009
comment
Ваше объяснение понятно. Мне интересно, почему у них нет подписи типа push_back(T const item) и избегают размещения new. - person Navaneeth K N; 07.11.2009
comment
Это создаст копию элемента, когда он будет передан в функцию (поскольку он передается по значению), чего избегает версия с передачей по ссылке. Можно избежать размещения new с помощью оператора =, но для этого потребуется, чтобы в этом месте уже был инициализированный объект (для вызова operator=), и, следовательно, требуется, чтобы T имел конструктор по умолчанию. - person Thomas; 07.11.2009
comment
Другое преимущество использования нового размещения заключается в том, что неиспользуемое пространство, выделенное вектором, но еще не заполненное, вообще не нужно инициализировать. Это небольшая оптимизация, если конструктор по умолчанию для T существует и мало что делает, но существенная разница, если конструктор по умолчанию для T выполняет много работы или имеет побочные эффекты. И, как указывает Томас, это позволяет T вообще не иметь конструктора без аргументов. - person Steve Jessop; 07.11.2009

C++ SDK всегда принимает const T & в качестве параметра функции для повышения эффективности.

В вашем случае, если он принимает T в качестве параметра, действие копирования будет выполнено дважды: одно для передачи его функции push_back(f), другое для внутреннего добавления в контейнер. И, принимая const T& в качестве параметра, нужна только одна копия!

person learner    schedule 15.09.2010

Он использует оператор размещения new и копирует его в унифицированную память;

Размещение new создает новый элемент по указанному адресу в памяти, в векторном случае текущий end();

void push_back(const T& val){
::new (&*end()) T(val);
[increase end]
}

посмотрите на http://spotep.com/dev/devector.h, код которого довольно понятен. (в отличие от большинства реализаций STL).

person Viktor Sehr    schedule 07.11.2009