Когда следует использовать прямую инициализацию и когда инициализация копирования?
Это просто предпочтение или есть конкретные случаи, когда одно необходимо перед другим? Я ссылаюсь на следующие варианты для инициализации
T t(e); // direct initialization
T t = e; // copy initialization
2 ответа
Фактические имена вещей, которые вы описываете, не являются неявным и явным назначением, но:
- Копия-инициализация:
T x = a;
- Прямая инициализация:
T x(a);
Они не эквивалентны, особенно в тех случаях, когда требуется преобразование, например, когда T
имеет тип класса и a
имеет другой тип (см. комментарий Alf для примеров контекстов, которые даже не включают преобразование). Рассмотрим следующий код:
class Test
{
public:
explicit Test(int i) { /* ... */ }
};
int main()
{
Test t(0); // OK : calls Test::Test(int)
Test u = 0; // KO : constructor is marked explicit
}
Перефразируя стандарт (8.5/14):
- Для прямой инициализации и копирования инициализации, когда тип источника совпадает или является производным классом класса назначения, рассматриваются конструкторы
- Для других случаев инициализации копирования, как вторая строка
main
в моем примере рассматриваются определяемые пользователем последовательности преобразования. Как использованиеTest
конструктор для неявного преобразования был запрещенexplicit
Ключевое слово, вторая строка не компилируется.
Прямая инициализация вроде
std::istringstream stream( "blah blah" );
необходимо, когда рассматриваемый тип, здесь std::istringstream
из стандартной библиотеки C++, не имеет доступного конструктора копирования.
Инициализация копии, как
std::istringstream stream = "blah blah"; //! NOT VALID
требует доступного конструктора копирования, потому что он выполняется так, как будто временный объект создается справа от =
и как будто это временное затем используется для инициализации объявленной переменной.
С другой стороны, в C++98 синтаксис инициализации копирования необходим для использования инициализаторов в фигурных скобках. Например, прямая инициализация не может быть использована для инициализации агрегата. Но вы можете использовать инициализацию копирования с помощью инициализатора фигурных скобок:
#include <string>
using namespace std;
struct Answer
{
int nVotes;
string description;
};
int main()
{
Answer const incorrect = { 26, "they're the same!" };
Answer const correct = { -1, "nah, they're different, actually" };
}
Итак, есть существенные различия.
Я обычно предпочитаю синтаксис инициализации копирования из-за ясности. Но иногда, как показано выше, прямая инициализация, к сожалению, необходима. Некоторые люди, например, автор учебника по С ++ Фрэнсис Глассбороу, вместо этого используют прямую инициализацию в качестве предпочтительного синтаксиса инициализации (я не уверен, почему, на мой взгляд, это менее понятно и представляет проблему "самого неприятного анализа"), и для них в некоторых случаях это является необходимостью инициализации копирования, что вызывает сожаление.
Ура & hth.,