Подтвердить что ты не робот

В чем разница между объявлением конструктора private и = delete?

Например, я хочу объявить класс, но я хочу, чтобы клиент не мог использовать конструктор копирования (или оператор присваивания копии)

Оба из следующих двух не позволяют использовать конструктор копирования:

1.

class Track
{
public:
  Track(){};
  ~Track(){};
private:
  Track(const Track&){};
};

2.

class Track
{
public:
  Track(){};
  ~Track(){};
  Track(const Track&)=delete;
};

Является ли один из этих способов "более правильным", чем другой, или равным? Есть ли побочный эффект?

//Does not compile with both the above ways
int main()
{
  Track l;
  Track p(l);
}
4b9b3361

Ответ 1

Сделать это частным - это "старый" способ сделать это. Конструктор все еще существует, но он является закрытым и может быть вызван только из другой функции-члена класса.

= delete удаляет конструктор. Он не генерируется компилятором, и его просто не будет.

Поэтому, скорее всего, = delete - это то, что вы хотите. (хотя с оговоркой, что не все компиляторы поддерживают этот синтаксис, поэтому, если переносимость является проблемой...)

Ответ 2

Объявление конструктора копирования private по-прежнему позволяет функциям-членам класса Track копировать экземпляры этого класса, при этом его удаление просто запрещает копирование этого объекта.

В С++ 11 удаление конструктора копии - это правильный способ выразить тот факт, что класс не копируется (если, конечно, нет смысла указывать функции-члены из Track или друзей Track, для объектов copy-construct Track).

Ответ 3

Создание закрытого конструктора в основном было "взломом" на старом С++, поскольку это был единственный способ помешать пользователям использовать их. Возможность delete специальных функций-членов была введена только в С++ 11, и это лучший и более идиоматический способ сказать, что класс не может быть скопирован. поскольку он явно о намерении.

Частные конструкторы имеют другие применения, кроме как запретить их использование полностью (например, они могут быть вызваны статическими функциями-членами класса). Поэтому просто создание закрытого конструктора не очень хорошо передает намерение, и полученная ошибка также не очень ясна.

Ответ 4

Ваш первый подход не мешает самому классу копировать себя. Традиционным способом решения этого является объявление частного экземпляра-копии и отказ от него.

Однако проблема в том, что намерение может быть не очевидным. Кто-то, читающий код, может не понимать, почему существует сиротская декларация, и может ошибочно удалить ее. Комментарии могут помочь, так же как и личное наследование от boost::noncopyable, если Boost доступен для вас.

Второй подход делает цель очевидной и является тем, что вы должны предпочесть, если вы можете использовать С++ 11.

Ответ 5

Ваше первое решение передает читателю, что конструктор-копир является закрытым и не должен использоваться. Ваше второе решение действует только в С++ 11. Из-за этого я бы сказал, что более переносимая и понятная реализация будет первой, используя частную собственность.

Ответ 6

Если вы находитесь на С++ 11, используйте delete. Причина в том, что он делает явный вызов и намерение понятным. Вы можете случайно использовать частный конструктор (например, в ограниченном наборе областей), но компилятор запретит вам использовать удаленный конструктор.

Одна из проблем частного конструктора заключается в том, что класс и друзья все еще могут его использовать - это приводит к ошибкам доступа, а также к ошибкам ссылок, которые могут быть трудно отследить на вызывающем сервере.

Если ваши необходимые инструментальные цепочки не поддерживают удаленные конструкторы (= delete), вы не должны определять его (как видно из вашего вопроса) - объявите его и оставьте его undefined, например: private: \n Track(const Track&);

Ответ 7

В первом случае вы по существу объявляете частный конструктор копирования и не предоставляете никакой реализации. Объявляя их частными, нечлены не могут его скопировать.

Во втором случае синтаксис запрещает создание копии. Это С++ native.

Основное отличие как программиста - читаемость и понимание кода. Первый случай избыточен, почему объявить конструктор копирования, сделать его закрытым и не реализовать. Клиент должен здесь много сделать.

Вы можете просто использовать "= удалить" и четко указать, что вы пытаетесь сделать.