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

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

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

Ответы [ 5 ]

37 голосов
/ 17 марта 2019

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

Я бы поместил их в секцию public .

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

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

20 голосов
/ 17 марта 2019

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

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

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

Если вы хотите поддерживать режимы C ++ 03 и C ++ 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;
};
14 голосов
/ 18 марта 2019

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

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

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

6 голосов
/ 30 января 2017

delete работает так же хорошо с private доступом.

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

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

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

2 голосов
/ 30 января 2017

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

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

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

...