В чем разница между объявлением конструктора 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);
}
Ответы
Ответ 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.
Основное отличие как программиста - читаемость и понимание кода. Первый случай избыточен, почему объявить конструктор копирования, сделать его закрытым и не реализовать. Клиент должен здесь много сделать.
Вы можете просто использовать "= удалить" и четко указать, что вы пытаетесь сделать.