В чем заключаются различия между неявно объявленными и неявно определенными конструкторами копирования?

Я просматриваю страницу cppreference на конструкторах копий здесь: http://en.cppreference.com/w/cpp/language/copy_constructor

Я прочитал 2 раздела о неявно объявленных конструкторах копий и неявно заданных конструкторах копий несколько раз, но я до сих пор не понимаю различия. Не будет ли неявно объявленный, но НЕ определенный конструктор привести к проблемам компоновщика?

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

Может кто-нибудь объяснить (проще говоря), какие различия/различия между этими двумя категориями?

Ответы

Ответ 1

Это поясняется в примечании в стандарте в начале раздела 12:

[Примечание: реализация будет неявно объявлять эти функции-члены для некоторых типов классов, когда программа явно не объявлять их. Реализация будет неявно определять их, если они используются odr (3.2).  См. 12.1, 12.4 и 12.8. - конечная нота]

Нормативные ссылки для С++ 14 (N3936) - 12.1/5, 12.4/6, 12.8/13, 12.8/26. В каждом случае соответствующая специальная функция-член неявно определяется, если она дефолтна и не определена как удаленная, и либо odr-используется, либо явно дефолт. Если у нас есть что-то вроде

struct Foo {};

и не создаются объекты типа Foo, все шесть специальных функций-членов (конструктор по умолчанию, деструктор, конструктор копирования, конструктор перемещения, оператор присваивания копии, оператор переадресации) неявно объявляются дефолтными, но не определенными с они не используются odr.

Ответ 2

Если существует неявно объявленный конструктор копирования, он всегда определяется 1. Варианты его определения:

  • зачеркнуть
  • тривиальна
  • неявно определяется

Если программа пытается использовать конструктор, который определен как удаленный, то программа плохо сформирована (т.е. вы получаете ошибку компилятора). В других случаях функция вызывается.

На странице, на которой вы ссылаетесь, описывается, в каких ситуациях происходит каждая из трех указанных выше опций.

С++ 11 добавила концепцию функции delete d, поскольку если вы хотите явно сделать класс не скопированным (и т.д.). Вы определяете его конструктор-копию как удаленный, а затем компилятор генерирует ошибку, если кто-то пытается скопировать ваш объект.

Различие между тривиально копируемым и не тривиально копируемым всегда было, но было сказано не так четко; вы вывели из правил о POD, в каких ситуациях было разрешено использовать memcpy для копирования объектов.

1 Как указывает Брайан, более точно сказать, что он определен, если требуется. Компилятор никогда не объявляет какую-либо функцию, а затем генерирует ошибку ссылки. Но если определение функции не требуется для успешной сборки исполняемого файла, это не повлечет за собой фактическое формирование определения.