Почему распределителю в С++ нужен конструктор копирования?

Говорят, здесь, что он из-за спецификации исключения. Я не понимаю. Имеет ли этот вопрос какое-либо отношение к спецификации исключения?

Ответ 1

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

allocator(const allocator&) throw();

и

template <class U> allocator(const allocator<U>&) throw();

хотя конструктор копирования бесполезен для распределителя. И ответ заключался в том, что спецификация распределителя не позволяет конструктору генерировать исключения. Поэтому публичный интерфейс конструктора копирования определяет конструкторы копирования с спецификацией исключения throw() (не генерирует каких-либо исключений), чтобы кто-то не получал свой собственный распределитель с конструкторами копирования, которые могли бы генерировать исключение.

См. эту ссылку для хорошего описания того, что такое спецификация исключения, если это то, что вас бросало. (На самом деле не каламбур).

Таким образом, они не означали, что при создании распределителя вы должны предоставить конструктор копирования. Они просто указывали, что спецификация специально запрещает вам определять то, которое выбрасывает какие-либо исключения. `

Ответ 2

Вы должны явно написать конструктор копирования (вместо использования по умолчанию), потому что конструктор копирования для распределителя С++ 03 должен быть определен с помощью спецификатора исключения throw(). Конструктор копии по умолчанию не имеет этого спецификатора.

Технически, вам это не обязательно, но если это действительно делает исключение... ну, удачи с этим.

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

Ответ 3

Распределитель требует конструктора копирования, потому что контейнеры имеют конструктор копирования и должны будут скопировать их распределитель в процессе.

Ответ 4

Это на самом деле довольно просто. Конструктор контейнера с использованием распределителя берет распределитель и сохраняет его копию. Для этого ему нужно, чтобы распределитель был CopyConstructible. Все это. Обратите внимание, что тип распределителя не требуется для CopyAssignable, если его признак propagate_on_container_copy_assignment не является истинным (что редко).

В спецификации С++ 11 также указано, что "ни один конструктор, оператор сравнения, операция копирования, операция перемещения или операция свопинга на этих типах не должны выходить через исключение". Правила исключений позволяют создавать (стек) копию распределителя (особенно при строительстве или уничтожении), не беспокоясь о том, что копирование распределителя будет выбрано. Проектирование контейнеров, исключающих безопасность в присутствии распределителей, которые могут бросать на копирование, перемещение, свопинг или сравнение, практически невозможно. На практике распределитель не может удерживать гораздо больше, чем указатель на какой-то ресурс, поэтому использование распределителей для копирования и т.д. Добавит много боли для практически никакого усиления.