Например, я хочу объявить класс, но хочу, чтобы клиент не мог использовать конструктор копирования (или оператор назначения копирования)
Оба из следующих двух не позволяют использовать конструктор копирования:
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);
}
Сделать это приватным — это «старый» способ сделать это. Конструктор все еще существует, но он является закрытым и может быть вызван только из другой функции-члена класса.
= delete
удалений конструктор Он не генерируется компилятором и просто не будет существовать.
Так что, скорее всего, = delete
это то, что вы хотите. (хотя с оговоркой, что не все компиляторы поддерживают этот синтаксис, так что, если переносимость является проблемой …)
Объявление конструктора копирования private
по-прежнему позволяет функции-члены Track
класс для копирования-создания экземпляров этого класса, в то время как удаление его просто запрещает копирование этого объекта.
В C ++ 11 удаление конструктора копирования — это верный способ выразить тот факт, что класс не подлежит копированию (если, конечно, не имеет смысла позволять функциям-членам Track
или друзья Track
скопировать-построить Track
объекты).
Создание частного конструктора было в основном «взломом» в старом C ++, поскольку это был единственный способ запретить пользователям использовать их. Способность к delete
специальные функции-члены были введены только в C ++ 11, и это лучший и более идиоматический способ сказать, что класс не может быть скопирован. так как это явно о намерение.
Частные конструкторы имеют другое использование, кроме полного запрещения их использования (например, они могут вызываться статическими функциями-членами класса). Таким образом, простое создание конструктора не очень хорошо передает намерение, и получающаяся ошибка также не очень ясна.
Ваше первое решение сообщает читателю, что конструктор копирования является частным и не должен использоваться.
Ваше второе решение действительно только в C ++ 11. Из-за этого я бы сказал, что более портативная и удобочитаемая реализация будет вашей первой, используя private-свойство.
В первом случае вы, по сути, объявляете конструктор частной копии, а затем не предоставляете никакой реализации. Объявив их закрытыми, пользователи, не являющиеся членами, не могут скопировать их.
Во втором случае синтаксис запрещает копирование. Это родной C ++.
Основное отличие программиста — читаемость и понимание кода. Первый случай является избыточным, зачем объявлять конструктор копирования, делать его закрытым и не реализовывать его. Клиент должен многое сделать здесь.
Вы можете просто использовать «= delete» и четко указать, что вы пытаетесь сделать.
Ваш первый подход не мешает самому классу копировать себя. Традиционный способ решить эту проблему — объявить конструктор копирования закрытым. а также оставить это невыполненным.
Проблема с этим, однако, заключается в том, что намерение не может быть очевидным. Кто-то, читающий код, может не понять, почему существует осиротевшее объявление, и может ошибочно удалить его. Комментарии могут помочь, как бы унаследовав от boost::noncopyable
если Boost доступен для вас.
Второй подход делает намерение очевидным и это то, что вы должны предпочесть, если вы можете использовать C ++ 11.
Если вы на C ++ 11, используйте delete
, Причина в том, что он делает вызов явным, а цель — ясной. Вы все еще можете случайно использовать приватный конструктор (например, в ограниченном наборе областей), но компилятор запретит вам использовать удаленный конструктор.
Одной из проблем приватного конструктора является то, что класс и друзья все еще могут его использовать — это приводит не к ошибкам доступа, а к ссылка на сайт ошибки, которые трудно отследить до места вызова.
Если ваши необходимые наборы инструментов не поддерживают удаленные конструкторы (= delete
), вы не должны определять это (как видно из вашего вопроса) — только объявлять и оставьте это неопределенным, например: private: \n Track(const Track&);