c ++ push back Создание дополнительной операции копирования [duplicate]

В Java переменные класса и экземпляра принимают значение по умолчанию (null, 0, false), если они не инициализируются вручную. Однако локальные переменные не имеют значения по умолчанию. Если локальной переменной не присвоено значение, компилятор откажется компилировать код, который его читает. IMHO, это приводит к выводу, что инициализация локальной переменной с некоторым значением по умолчанию (например, null, которое может привести к NullPointerException позже), когда оно объявлено, на самом деле плохо. Рассмотрим следующий пример:

  Object o;  если (& lt; некоторое булево условие & gt;) o = & lt; некоторое значение & gt ;;  else o = & lt; некоторое другое значение & gt ;;  System.out.println (о);   

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

Это выполняется для Java и, возможно, только для Java. Я не знаю о языке, как C #. Тем не менее, в хорошем старом C (и, возможно, C ++), всегда рекомендуется инициализировать переменные при объявлении их AFAIK. Такие «старые школьные» языки программирования могут быть причиной того, что рекомендация всегда инициализировать переменные появляется в книгах и дискуссиях о современных языках, таких как Java, где компилятор отслеживает, была ли инициализирована переменная или нет.

4
задан 0x499602D2 4 November 2014 в 17:49
поделиться

4 ответа

Что происходит:

  1. x вставлен через push_back. Возникает одна копия: вновь созданный элемент инициализируется аргументом. my_int берется как ноль, потому что конструктор по умолчанию x s инициализировал его так.
  2. Второй элемент - push_back 'd; Вектор должен перераспределить память, так как была достигнута внутренняя емкость . Поскольку конструктор перемещения неявно определен для Myint 1, выбран конструктор копирования; Первый элемент копируется во вновь выделенную память (его my_int все еще ноль ... поэтому конструктор копирования снова показывает my_int как 0), а затем x копируется для инициализации второго элемента (как в случае с первый в шаге 1). На этот раз x задано значение my_int, и это говорит нам вывод конструктора копирования.

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

Вы можете уменьшить количество копий за счет резервирования большего объема памяти, то есть увеличить емкость векторов, чтобы перераспределение стало ненужным:

myints.reserve(2); // Now two elements can be inserted without reallocation.

Кроме того, вы можете высвободить копии при вставке следующим образом:

myints.emplace_back(0);

Этот «emplaces» новый элемент - emplace_back является вариационным шаблоном и поэтому может принимать произвольное количество аргументов, которое оно затем пересылает - без копий или движений - в конструктор элементов.

1 Поскольку существует конструктор, созданный пользователем.

10
ответ дан Columbo 16 August 2018 в 02:39
поделиться

Вы правы в предположении, что дополнительный вызов конструктора копирования происходит из внутренней реструктуризации вектора.

Подробнее см. в этом ответе: https://stackoverflow.com/a / 10368636/3708904

Или этот ответ по причине необходимости создания копии: https://stackoverflow.com/a/11166959/3708904

3
ответ дан Community 16 August 2018 в 02:39
поделиться

Когда размер вектора увеличивается со вторым push_back, существующее содержимое вектора должно быть скопировано в новый буфер. Чтобы проверить вывод myints.capacity() после первого push_back, он должен быть 1.

3
ответ дан Mark Ransom 16 August 2018 в 02:39
поделиться
  • 1
    Несвязанный: почему этот же пример дает вывод 0 1 0 вместо 0 0 1 в коде OP? – 0x499602D2 4 November 2014 в 17:57
  • 2
    @ 0x499602D2 возможно, что реализация копирует элемент push_back в новый буфер, прежде чем он копирует старый буфер. – Mark Ransom 4 November 2014 в 17:59

Это зависит от того, сколько памяти зарезервировано для объекта типа std::vector. Похоже, что когда push_back был впервые выполнен, выделено память только для одного элемента. Когда был вызван второй раз push_back, память была перераспределена для резервирования памяти для второго элемента. В этом случае элемент, который уже находится в векторе, копируется в новом месте. И затем добавляется второй элемент.

Вы можете зарезервировать достаточно памяти самостоятельно, чтобы избежать второго вызова конструктора копирования:

vector<Myint> myints;
myints.reserve( 2 );
3
ответ дан Vlad from Moscow 16 August 2018 в 02:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: