В чем различие между неявно объявленными и неявно определенными конструкторами копирования?
Я просматриваю страницу cppreference для конструкторов копирования здесь: http://en.cppreference.com/w/cpp/language/copy_constructor
Я прочитал 2 раздела, касающихся неявно объявленных конструкторов копирования и неявно определенных конструкторов копирования, но я до сих пор не понимаю различия. Не приведет ли неявно объявленный, но НЕ определенный конструктор к проблемам с компоновщиком?
Правила очень сложны. Я не помню, чтобы в C++03 было различие: либо у вас был конструктор копирования, сгенерированный компилятором, либо нет.
Может ли кто-нибудь объяснить (более простыми словами), каковы различия / различия между этими двумя категориями?
2 ответа
Это поясняется в примечании к стандарту в начале пункта 12:
[ Примечание: Реализация будет неявно объявлять эти функции-члены для некоторых типов классов, когда программа явно не объявляет их. Реализация будет неявно определять их, если они используются odr (3.2). См. 12.1, 12.4 и 12.8. - конец примечания ]
Нормативные ссылки для C++14 (N3936): 12,1/5, 12,4/6, 12,8/13, 12,8/26. В каждом случае соответствующая специальная функция-член определяется неявно, если она имеет значение по умолчанию и не определена как удаленная, либо используется odr, либо используется явно по умолчанию. Если у нас есть что-то вроде
struct Foo {};
и нет объектов типа Foo
когда-либо созданы, все шесть специальных функций-членов (конструктор по умолчанию, деструктор, конструктор копирования, конструктор перемещения, оператор назначения копирования, оператор назначения перемещения) неявно объявляются как значения по умолчанию, но не определены, так как они не используются в odr.
Если существует неявно объявленный конструктор копирования, он всегда определяется1. Варианты его определения:
- удаленный
- тривиальный
- неявно определяется
Если программа пытается использовать конструктор, который определен как удаленный, значит, программа некорректна (т.е. вы получаете ошибку компилятора). В остальных случаях вызывается функция.
На странице, на которую вы ссылаетесь, описано, в каких ситуациях встречается каждый из трех приведенных выше вариантов.
C++ 11 добавил концепцию delete
Функция d, когда вы хотите явно сделать класс не подлежащим копированию (и т. д.). Вы определяете его конструктор копирования как удаленный, а затем компилятор генерирует ошибку, если кто-то пытается скопировать ваш объект.
Различие между тривиально копируемым и нетривиально копируемым существовало всегда, но оно не было сформулировано достаточно четко; вы вывели из правил о POD, в каких ситуациях было разрешено использовать memcpy
копировать объекты.
1 Как указывает Брайан, правильнее будет сказать, что он определен, если требуется. Компилятор никогда не объявляет функцию, а затем генерирует ошибку ссылки. Но если определение функции не требуется для успешной сборки исполняемого файла, оно не будет беспокоиться о формировании определения.