Назначьте * this для делегирования конструктора - PullRequest
4 голосов
/ 07 февраля 2012

Я смотрел на некоторые новые функции в C ++ 11, и из-за моей текущей версии GCC я не могу использовать делегирование конструктора.Но это заставило меня задуматься о репликации этой функции следующим образом:

class A
{
public:
    A() : num( 42 ) {}
    A( int input ) { *this = A(); num *= input; }

    int num;
};

Она, безусловно, компилируется и работает нормально, код ниже:

A a;
cout << "a: " << a.num << endl;
A b( 2 );
cout << "a: " << b.num << endl;

Возвращает это, что правильно.

42
84

Очевидно, что это очень тривиальный пример, но кроме неэффективности памяти (два A созданы и один перезаписан другим перед уничтожением), какие проблемы могут возникнуть?Это, конечно, похоже на запах кода, но я не могу придумать действительно вескую причину, почему.

Ответы [ 2 ]

1 голос
/ 07 февраля 2012

Вы не инициализируете свой объект целым числом, но модифицируете инициализированный объект по умолчанию.Это может или не может быть проблемой.Довольно часто люди учитывают общие функции в некоторых init() функциях, чтобы иметь такую ​​же функциональность, как делегирование ctors.Однако в некоторых ситуациях это нежелательно / неправильно / невозможно:

  • когда у вас есть ссылочный элемент, вы должны инициализировать его в ctor, вы не можете инициализировать его по умолчанию и затем перезаписать,Вместо этого может помочь указатель.
  • для определенных элементов, инициализация по умолчанию делает что-то, а перезапись - что-то дополнительное.С точки зрения производительности, было бы более эффективно сразу инициализировать член.В зависимости от того, что делает инициализация, это может быть просто снижение производительности, но для некоторых побочных эффектов объекта это может быть даже неправильная плоскость.
  • Элемент может не быть назначаемым.

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

Но YMMV.

0 голосов
/ 07 февраля 2012

Ваш код вообще не является C ++ 11.Я думал о том, могут ли здесь работать конструкторы перемещения, поскольку вы по сути перемещаете один А в другой, а затем слегка его модифицируете.

Как и в случае с C ++ 03, вы можете оптимизировать инициализацию, которую хотите выполнить один раз, во всех ваших конструкторах.либо помещая их в подкласс, либо в базовый класс (часто с защищенным или частным наследованием, поскольку это деталь реализации).Используя базовый класс:

class ABase
{
protected:
  int num;

  ABase() : num(42) {}
};

class A : protected ABase
{
public:
   A() = default; // or in C++03 just {}
   explicit A(int input) : ABase()
   {
       num *= input;
   }
};

(Вы можете изменить свои права доступа по вкусу).Проблема здесь в том, что я создаю только один объект «ABase», и если он имеет больше, чем просто тривиальный член int, это может быть важно.Мне очень нравится наследование, поскольку я затем использую его в A в качестве члена класса, а не члена какого-либо агрегированного объекта, и я предпочитаю наследование, защищенное или частное, здесь, но иногда, если в базовом классе есть члены, которые я хочу быть общедоступными, я будуиспользовать публичное наследование, но дать базовому классу защищенный деструктор.Это при условии, что нет v-таблицы, и, следовательно, дальнейшее получение не ожидается.(На самом деле вы можете завершить A здесь, сделав наследование виртуальным и частным, но вы, вероятно, не хотите).

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