Когда следует использовать прямую инициализацию и когда инициализация копирования?

Это просто предпочтение или есть конкретные случаи, когда одно необходимо перед другим? Я ссылаюсь на следующие варианты для инициализации

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.,

Другие вопросы по тегам