Когда следует использовать прямую инициализацию и когда инициализация копирования? - PullRequest
14 голосов
/ 27 ноября 2010

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

T t(e); // direct initialization
T t = e; // copy initialization

Ответы [ 2 ]

19 голосов
/ 27 ноября 2010

Фактические названия вещей, которые вы описываете, не являются неявным и явным присвоением, но:

  • Копирование-инициализация: T x = a;
  • Прямая инициализация: T x(a);

Они не эквивалентны, особенно в тех случаях, когда требуется преобразование, например, когда T относится к типу класса, а a - к другому типу (см. Alf comment для примеров контексты, которые даже не включают преобразование). Рассмотрим следующий код:

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, вторая строка не компилируется.
10 голосов
/ 28 ноября 2010

Прямая инициализация подобно

std::istringstream  stream( "blah blah" );

необходима, когда рассматриваемый тип, здесь std::istringstream из стандартной библиотеки C ++, не имеет доступного конструктора копирования.

A инициализация копирования , как и

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" };
}

Итак, есть существенные различия.

Я обычно предпочитаю синтаксис инициализации копирования из-за ясности.Но иногда, как показано выше, прямая инициализация, к сожалению, необходима.Некоторые люди, например, автор учебника по С ++ Фрэнсис Глассбороу, вместо этого получили прямую инициализацию в качестве предпочтительного синтаксиса инициализации (я не уверен, почему, на мой взгляд, это менее понятно и представляет проблему «самого неприятного анализа»), и для нихв некоторых случаях это является необходимостью инициализации копирования, что вызывает сожаление.

Cheers & hth.,

...