Почему данные присваиваются без создания дополнительной копии в списке инициализации? - PullRequest
5 голосов
/ 13 июля 2011

Parashift хорошо объясняет списки инициализации, но не объясняет , почему дополнительная копия переменной создается перед присваиванием в теле ctor, но дополнительная копия не создается при назначении черезсписок инициализации.
Я даже наткнулся на совет использовать ++ i вместо i ++, потому что первый избегает создания временного i перед присваиванием.То же самое для POD, назначенных в теле ctor?Временная переменная создается до того, как произойдет присваивание?

Другими словами, зачем компилятору создавать дополнительную копию переменной?Почему нельзя просто присвоить переменную напрямую?
Почему?

Ответы [ 3 ]

3 голосов
/ 13 июля 2011

Рассмотрим следующее:

struct C { 
    C() { /* construct the object */ }
};

struct X {
    C member;

    X() { member = C(); }
};

Конструктор X() такой же, как если бы вы сказали:

X() : member() { member = C(); }

Во-первых, конструктор C вызывается для конструированияmember элемент данных.Затем выполняется тело X, создается второй временный объект C, которому назначается member, а затем временный объект уничтожается.


Обратите внимание, что это относится только ктипы, которые инициализируются автоматически.Если бы member был типа int или типа класса POD (как примеры), он был бы неинициализирован при вводе тела конструктора X.

Для таких типов это не такс точки зрения производительности действительно важно, инициализируете ли вы элемент данных в списке инициализации или назначите элемент данных в теле конструктора;разница полностью стилистическая.Там, где это возможно, список согласованности все же следует отдавать предпочтение ради согласованности.

2 голосов
/ 13 июля 2011

почему дополнительная копия переменной создается перед присвоением в тело ctor, но при назначении через список инициализации.

Поскольку назначение следует за инициализацией. Другими словами, присваивание необязательно, но инициализация обязательна. Вы можете не заметить большой разницы для POD. Но то же самое относится и к пользовательским типам данных.

советы по использованию ++ i вместо i ++

Опять же, для POD это не имеет большого значения. Но для пользовательских классов i++ создает временную копию. Так что лучше использовать ++i.

struct A {
  A operator ++ (int)  // example of i++
  {
    A temp = *this;
    this->value ++;
    return temp;    // makes 2 copies "temp" and return value
  }
  A& operator ++ ()  // example of ++i
  {
    this->value ++;
    return *this;  // no copy
  }
};
2 голосов
/ 13 июля 2011

Чтобы ответить на ваш первый вопрос, конкретно касающийся копии (не касаясь "++ i" против "i ++"):

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...