Чтобы сделать объект некопируемым, мы можем явно удалить его конструктор копирования и оператор присваивания копии.
Мой вопрос: где правильно это сделать - в разделе public
, private
или protected
класса? И - имеет ли этот выбор значение?
Чтобы сделать объект некопируемым, мы можем явно удалить его конструктор копирования и оператор присваивания копии.
Мой вопрос: где правильно это сделать - в разделе public
, private
или protected
класса? И - имеет ли этот выбор значение?
где это лучше сделать - в общедоступном, приватном или защищенном разделе класса?
Я бы поместил их в раздел public
.
Это связано с тем, что удаление конструктора или оператора присваивания ортогонально их созданию private
/ protected
; и когда они не удаляются, по умолчанию они public
. Помещение удалений в один из этих двух разделов кажется мне намеком: «Если бы я не удалил их, я бы сделал их частными/защищенными» — это не то сообщение, которое вы хотите передать в вашем случае.
Обратите внимание, однако, что компилятору все равно, в какой раздел вы помещаете удаление.
Именно это. Когда-то мы делали эти вещи приватными специально для того, чтобы запретить людям доступ к ним, но это всегда был взлом и был только потому что мы не могли delete
их. Это соображение больше не играет роли. Я не помню, имеет ли диагностика «копирующий конструктор является закрытым» приоритет над диагностикой «копирующий конструктор удален» (я сомневаюсь в этом), но даже если он не меняет уровень доступа, это неправильно. по указанным вами причинам.
@LightnessRacesinOrbit Я знаю, что видел, как некоторые компиляторы выдают обе ошибки, когда функция закрыта и удалена. То, что касается приватного доступа, становится просто лишним шумом.
@aschepler Fair делает
gcc 7.4, но не gcc 8.1: godbolt.org/z/udzwB2 (так что, я думаю, они улучшили это).
@aschepler: Хм ... вы переключили вкладки вывода, так что похоже, что 7.4 делает все правильно. В любом случае, спасибо.
Хм. Я думаю, что они были расположены правильно, когда я нажал «Поделиться». Ну что ж.
Из книги Скотта Мейерса, Effective Modern C++ (статья 10), кажется, что лучше определить их как public:
По соглашению удаленные функции объявляются общедоступными, а не частными. На это есть причина. Когда клиентский код пытается использовать элемент Функция C++ проверяет доступность перед удалением статуса. Когда клиент код пытается использовать удаленную приватную функцию, некоторые компиляторы жалуются только о том, что функция является частной, хотя функция доступность на самом деле не влияет на возможность его использования. Это стоит имея это в виду при пересмотре устаревшего кода для замены частные и неопределенные функции-члены с удаленными, потому что обнародование новых функций, как правило, приводит к лучшей ошибке сообщения.
Кроме того, я считаю, что удаленный конструктор/назначение копии должен быть частью интерфейса класса, который должен быть доступен ВСЕМ пользователям класса. Такая информация не должна храниться в секрете, делая ее частной.
Мейерс противоречит ответу Рассказчика и моим тестам. Это все еще хороший совет, но я считаю, что рассуждения einpoklum лучше.
@LightnessRacesinOrbit Я проверил VS2013. Сообщение об ошибке отличается от g++ и правильно показывает ошибку. Кроме того, с концептуальной точки зрения, когда класс удаляет ctor/cctor и т. д., класс хочет сказать ВСЕМ своим клиентам, что: «Эй, этот член удален, и вам не разрешено его использовать». . В этом факте нет секрета, чтобы держать его в секрете.
Согласованный; это рассуждение einpoklum, которое я нахожу превосходным;)
Имеет ли какое-либо значение расположение удаленного определения?
С чисто языковой точки зрения это не имеет абсолютно никакого значения. Поиск имени и разрешение перегрузки происходят до проверки доступа. И попытка сослаться на удаленную функцию в конце разрешения перегрузки делает вашу программу неправильной, и точка. Компилятор может выдать или не выдать другую диагностику доступности, но в программе уже есть ошибка, о которой необходимо сообщить.
Таким образом, вы можете поместить это удаленное определение с любой доступностью, какой пожелаете. Я думаю, что большинство будет держать его закрытым, чтобы соответствовать «старой» практике сделать класс некопируемым (поместить объявление этих членов в частный раздел класса, а не определять их), хотя бы для того, чтобы помочь тем кто знает старые способы "получить его" раньше. Смесь идиом, если хотите.
Отметить как частный также нельзя, если вам нужна поддержка режима 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;
};
Если вам нужна обратная совместимость, то это обязательно.
@LightnessRacesinOrbit Если вам нужна обратная совместимость, НИКОГДА не используйте функции C++11. В случае удаленных функций StoryTeller предлагает обходной путь. Но каково решение обратной совместимости при использовании лямбда-выражений, stl, параллелизма и т. д.?
@hsalimi Пока вы можете использовать функции C ++ 11, если вам нужен полезный уровень совместимости, правда, но у меня была библиотека среды событий в предыдущем проекте, которую можно было скомпилировать либо на C ++ 03, либо на C + +11 (он по-прежнему использовался в устаревших встроенных проектах), и в последнем случае он имел кучу оптимизаций (в основном связанных с ссылками rvalue), которые значительно улучшили ситуацию, не слишком сильно перегружая интерфейс. Мне действительно нужно было переключаться между Boost.Thread и std::thread
, но тогда в последнем случае это облегчает зависимость от библиотеки (и ссылки!), Так что это не напрасно.
@hsalimi Но да, это означало, что я не мог использовать лямбда-выражения в библиотеке ... или, по крайней мере, это было бы больше проблем, чем того стоило.
delete
работает так же хорошо с доступом private
.
Эффект delete
заключается в том, чтобы вызвать ошибку, если функция выбрана по разрешению перегрузки.
Эффект private
заключается в том, чтобы вызвать ошибку, если функция выбрана разрешением перегрузки вне класса или его друзей.
Если применимы обе ошибки, окончательный результат будет одинаковым в любом случае, но public
может помочь избежать сообщений компилятора о привилегиях доступа, которые могут вызвать путаницу.
Удаленные функции рекомендуется сделать общедоступными. См. coderhelper.com/a/18931192/108238. Также Clang-Tidy предлагает это.
Доступ к функции delete
d не имеет значения. Фактически, для членов класса было бы разумнее добавить дополнительный спецификатор доступа (delete:
). Я подозреваю, что причина, по которой они этого не сделали, заключалась в том, что это не сработает для функций, не являющихся членами.
Для таких вещей, как конструктор копирования, стилистически более целесообразно поместить его в раздел public
. Тот факт, что класс не имеет конструктора копирования, является довольно важным фактом, который необходимо знать об интерфейсе класса.
Для внутренних функций, в которых вы объявляете определенную перегрузку как удаленную, чтобы получить обнаружение ошибки во время компиляции, имеет смысл объявить функцию в том же разделе, что и все другие перегрузки.
function_name() = delete;
является новым для C++11. Если вы хотите поддерживать C++98/03, вы не можете его использовать.Если вы выбрасываете старую обувь, задумываетесь ли вы о том, где ее хранить?
@Клаус: Нет, но ты думаешь, куда их бросить...