Различия между инициализацией прямого списка и инициализацией списка копий

Я хотел бы знать, есть ли разница в следующих двух типах инициализации std::vector в С++ 11 и более поздних версиях.

std::vector<int> v1 {1, 2, 3, 4, 5};
std::vector<int> v2 = {1, 2, 3, 4, 5};

Вот полный пример кода, который отлично работает.

#include <iostream>
#include <vector>

int main()
{
    std::vector<int> v1 {1, 2, 3, 4, 5};
    std::vector<int> v2 = {1, 2, 3, 4, 5};

    std::cout << v1.size() << '\n';
    std::cout << v2.size() << '\n';
}

Я вижу обе инициализации, приводящие к одинаковым результатам.

Пример в http://en.cppreference.com/w/cpp/container/vector использует второй тип, поэтому я подумал, имеет ли такая инициализация какое-либо преимущество.

В общем, я хочу знать, имеет ли одна инициализация конкретное техническое преимущество над другим, или если одна инициализация считается лучшей практикой, а другая - нет, и если да, то почему.

В частности, меня беспокоит, есть ли у инициализации списка копий дополнительные накладные расходы из-за временных объектов и копирования?

Ответ 1

Инициализация списка неофициально называется "равномерной инициализацией", поскольку ее значение и поведение должны быть одинаковыми независимо от того, как вы его вызываете.

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

[dcl.list.init] объясняет синтаксическую разницу между прямым списком и списком копий. То есть он описывает, какие формы инициализации списка являются прямыми и копиями. Но он никогда не определяет функциональную разницу между ними.

Единственная часть стандарта, которая определяет поведенческую разницу, находится в [over.match.list]/1:

В инициализации списка копий, если выбран explicit конструктор, инициализация плохо сформирована.

Это функция разрешения перегрузки.

Поскольку стандарт не определяет поведенческую разницу, я был бы очень удивлен, если бы компиляторы решили наложить на них некоторую функциональную разницу.

Ответ 2

Я очень предпочитаю инициализацию копирования списка в целом (и особенно в случае std::vector), так как инициализация прямой список очень похож на взгляд std::vector явных конструкторов, когда есть только один или два элемента.

std::vector<int> x(2);
// is very different from
std::vector<int> x{2};

Явное указание на то, что я назначаю начальное значение вектору и не настраивая его со значениями, менее подвержено ошибкам.