Удаление copy-ctor и copy-assignment - общедоступное, частное или защищенное? - программирование

Удаление copy-ctor и copy-assignment - общедоступное, частное или защищенное?

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

У меня такой вопрос: каково это место - в public, private или protected части класса? И - этот выбор имеет значение?

4b9b3361

Ответ 1

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

Я бы поставил их в public разделе.

Это связано с тем, что удаление конструктора или оператора присваивания является ортогональным к тому, чтобы сделать их private/protected; и когда они не удаляются, они являются public по умолчанию. Помещение удалений в один из этих двух разделов напоминает мне подсказку "Если бы я не удалил их, я бы сделал их личными/защищенными" - это не сообщение, которое вы хотите передать в вашем случае.

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

Ответ 2

Имеет ли какое-то значение то, куда мы помещаем удаленное определение?

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

Таким образом, вы можете поместить это удаленное определение с любой доступностью по вашему желанию. Я думаю, что большинство будет держать его в тайне, чтобы соответствовать "старой" практике создания класса, не подлежащего копированию (поместите объявление этих членов в закрытый раздел класса, а не определяйте их), хотя бы для того, чтобы помочь кто знает старые способы "получить его" раньше. Смесь идиом, если хотите.

Пометить как частное также нельзя, если вам нужно поддерживать режимы С++ 03 и С++ 11. С помощью макроса можно легко создать заголовок для соответствия обоим стандартам:

#if __cplusplus >= 201103L
  #define DELETED_DEFINITION = delete
#else
  #define DELETED_DEFINITION
#endif

class noncopyable {
private:
  // This header can be compiled as both C++11 and C++03
  noncopyable(noncopyable const&) DELETED_DEFINITION;
  void operator=(noncopyable const&) DELETED_DEFINITION;
};

Ответ 3

Из книги Скотта Мейерса, "Эффективное современное" C++ (пункт 10), кажется, что лучше определить их как публичные:

По соглашению удаленные функции объявляются общедоступными, а не частными. Есть причина для этого. Когда клиентский код пытается использовать функцию-член, C++ проверяет доступность перед удалением статуса. Когда клиентский код пытается использовать удаленную приватную функцию, некоторые компиляторы жалуются только на то, что эта функция закрыта, хотя доступность функций не влияет на возможность ее использования. Стоит помнить об этом при пересмотре унаследованного кода с целью замены закрытых и не определенных функций-членов удаленными, потому что обнародование новых функций обычно приводит к улучшению сообщений об ошибках.

Кроме того, я считаю, что конструктор/назначение удаленных копий должны быть частью интерфейса класса, который должен быть доступен ВСЕМ пользователям класса. Такая информация не должна храниться в секрете, делая ее конфиденциальной.

Ответ 4

delete работает так же, как и при private доступе.

Эффект delete - вызвать ошибку, если функция выбрана с помощью разрешения перегрузки.

Эффект private вызывает ошибку, если функция выбрана с помощью разрешения перегрузки вне класса или его друзей.

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

Ответ 5

Доступ к функции delete d не имеет значения. Фактически, для членов класса было бы разумнее добавить дополнительный спецификатор доступа (delete:. Я подозреваю причину, по которой они этого не сделали, было то, что он не будет работать для функций, не являющихся членами.

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

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