Исключительная безопасность неявно сгенерированного оператора присваивания C ++

Насколько я понимаю, оператор присваивания неявно сгенерированный C ++ выполняет поэлементную копию (это, похоже, подтверждается также этот ответ). Но если во время копирования члена возникает исключение (например, потому что ресурс для этого члена не может быть выделен), будет ли копируемый объект застрять в недопустимом состоянии?

Другими словами, обеспечивает ли неявно созданный оператор присваивания только базовую гарантию, но не строгую гарантию?

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


person Mr.C64    schedule 12.11.2012    source источник
comment
Ресурс не может быть выделен, если вы имеете в виду элемент данных указателя, для которого используется память, тогда оператор присваивания уже не обслуживает его. Мудрая копия по умолчанию просто скопирует тот же адрес в новый указатель. Это классическая причина, по которой мы пишем конструкторы копирования.   -  person fkl    schedule 12.11.2012
comment
@ Mr.C64 в соответствии со стандартным оператором присваивания C ++ 11 неявно генерируется, но копирует оператор присваивания.   -  person spin_eight    schedule 12.11.2012
comment
@fayyazkl: Нет, я не имею в виду необработанные элементы данных указателей. Я думаю о классе C ++ RAII, который имеет члены данных, которые являются менеджерами ресурсов RAII (а не необработанными указателями).   -  person Mr.C64    schedule 12.11.2012
comment
@spin_eight: неявно сгенерированный оператор присваивания является оператором присваивания копии. Я не думаю, что здесь есть какая-то двусмысленность (кроме того, что C ++ 11 вводит назначение перемещения, но это не то, о чем спрашивает г-н C64, поскольку он не выполняет поэлементное копирование) .   -  person Steve Jessop    schedule 12.11.2012


Ответы (1)


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

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

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

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

person Steve Jessop    schedule 12.11.2012
comment
На некоторых очень простых классах основная гарантия может быть получена «случайно». Но если ваш класс удовлетворяет это, вам необходимо задокументировать, почему достаточно неявно сгенерированного оператора присваивания, что требует примерно тех же усилий, что и написание собственного. Вам нужно хотя бы подумать об этом. - person Tobias Langner; 12.11.2012
comment
@TobiasLangner: согласен. Например, если элементы данных класса ортогональны, что означает, что инварианты класса не подразумевают никакой связи между значениями членов, тогда вы получите базовую гарантию. - person Steve Jessop; 12.11.2012
comment
Спасибо, ребята, что указали на сохранение инвариантов классов (я пропустил это требование). - person Mr.C64; 12.11.2012
comment
@SteveJessop: Вы можете выделить жирным шрифтом ключевую часть вашего ответа: Если вы хотите предложить гарантию исключения, а оператор присваивания по умолчанию не nothrow, то обычно вам нужно написать его.. Кстати: подходит ли идиома копирования и обмена, чтобы предложить надежную гарантию? Или тоже есть подводные камни? - person Mr.C64; 12.11.2012
comment
@ Mr.C64: копирование и своп дает надежную гарантию при условии, что своп не будет заменен. Доказательство простое: ни один из объектов не изменяется до обмена, исключения генерируются только до обмена, поэтому при возникновении исключения ничего не изменяется. Было бы достаточно, чтобы своп был строго безопасным, но обычно вы хотите, чтобы своп не выполнялся по другим причинам. Главный из них заключается в том, что если вам нужно сделать два свопа, и каждый из них является строго безопасным, из этого не следует, что комбинированный оператор является строго безопасным. Но две безотказные операции в сумме дают бесполезную операцию. - person Steve Jessop; 12.11.2012