Когда я инициализирую контейнер C ++ (такой как std :: list), вызывается конструктор копирования? - PullRequest
3 голосов
/ 29 сентября 2011

Когда я инициализирую контейнер STL, например list< vector<char> >, используя, например, my_list.push_back(vector<char>(5000, 'T')) это копируется после строительства? Или компилятор вызывает конструктор внутри list< vector<char> >?

Ответы [ 2 ]

7 голосов
/ 29 сентября 2011

В C ++ 03 push_back определяется как void push_back(const T& x);. Это означает, что вы создаете vector, и константная ссылка на такой временной объект передается в list. Затем list внутренне вызывает конструктор копирования, чтобы сохранить копию такого элемента.

В C ++ 11 есть дополнительное определение для void push_back(T&& x);, которое принимает ссылку на rvalue к вашему временному vector и приведет к внутреннему вызову конструктора перемещения для инициализации копии, хранящейся в list.

0 голосов
/ 01 октября 2011

Компиляторы умные.Действительно умный.В этом случае есть оптимизация, называемая «копирование, удаление».Стандарт C ++ позволяет компилятору опускать копию, когда временный объект используется для инициализации объекта того же типа, а конструктор копирования указанного объекта не имеет побочных эффектов.

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

Вот пример программы.На gcc 4.4.5 с обоими -O0 и -O3 этот код приводит к печати «1».Я думаю, что GCC здесь не так ... некоторые компиляторы будут выводить «2», указывая, что копия произошла.Это то, где вещи становятся хитрыми при попытке обнаружить поведение, которое должно быть необнаружимым.В одном из этих компиляторов единственный способ определить это - погрузиться в получившуюся сборку.

#include <iostream>

struct elision
{
    explicit elision(int i) : v(i) {
    }

    elision(elision const &copy) : v(copy.v+1) {
    }

    int v;
};

int main()
{
    elision e(elision(1));
    std::cout << e.v << std::endl;
    return 0;
}
...