Exception-safety of C++ implicitly generated assignment operator
Asked Answered
T

1

19

My understanding is that C++ implicitly generated assignment operator does a member-wise copy (this seems confirmed also by this answer). But, if during a member copy an exception is thrown (e.g. because a resource for that member can't be allocated), will the object being copied be stuck in an invalid state?

In other words, does the implicitly generated assignment operator achieve only the basic guarantee, but not the strong guarantee?

If we want the strong guarantee for our class copies, must we implement the assignment operator manually with the copy-and-swap idiom?

Tarryn answered 12/11, 2012 at 9:48 Comment(4)
"resource cannot be allocated", if you mean a pointer data member for which memory is malloced, then assignment operator already does not cater it. The default member wise copy will just copy the same address into the new pointer. This is the classical reason why we write copy constructorsGayelord
@Tarryn according to the C++ 11 standart assignement operator not implicitly generated, but copy assignement operator does.Arouse
@fayyazkl: No, I don't mean raw pointers data members. I'm thinking of a C++ RAII class that has data members which are RAII resource managers (not raw pointers).Tarryn
@spin_eight: the implicitly generated assignment operator is a copy assignment operator. I don't think there's any ambiguity here (other than that C++11 introduces move assignment, but that's not what Mr.C64 is asking about since it doesn't do a member-wise copy).Blida
B
15

If you want to offer an exception guarantee, and the default assignment operator is not nothrow then normally you need to write one.

The default copy assignment doesn't necessarily achieve even the basic guarantee, which is that no resources are leaked and the class invariants are preserved. Assigning some of the data members but not all might leave the target in a state where class invariants are not satisfied, depending on the particular class.

So you have to assess the default operator for your class -- if it can throw, and by throwing leave the object in an "invalid" state, then you have to suppress it. Or weaken the defined class invariants, but that's not very helpful to users.

There is (at least) one special case. If all the data members except for one have nothrow assignment, and the special one has strongly exception-safe assignment, and is the first data member in the class, then the default assignment operator would also be strongly safe. You might want to comment that quite carefully if you're relying on it, though, it could prove to be quite fragile!

Blida answered 12/11, 2012 at 9:52 Comment(5)
On some very simple classes, the basic guarantee may be achieved 'by accident'. But if your class satisfies this, you need to document why the implicitly generated assignment operator is sufficient which is about the same effort as writing a custom one. You need at least think about it.Affinal
@TobiasLangner: agreed. For example if the data members of the class are "orthogonal", meaning that the class invariants don't imply any relationship between the values of the members, then you'd get the basic guarantee.Blida
Thanks guys for pointing out about preserving class invariants (I missed that requirement).Tarryn
@SteveJessop: You may want to format in bold the key part of your answer: If you want to offer an exception guarantee, and the default assignment operator is not nothrow then normally you need to write one.. BTW: Is copy-and-swap idiom OK to offer the strong guarantee? Or are there any gotchas, too?Tarryn
@Mr.C64: copy-and-swap gives the strong guarantee provided that swap is nothrow. The proof is simple: neither object is modified prior to the swap, exceptions are only thrown prior to the swap, so nothing is modified when an exception is thrown. It would be sufficient for the swap to be strongly-safe, but normally you want swap to be nothrow for other reasons. The main one is that if you need to do two swaps and each is strongly-safe, it doesn't follow that the combined op is strongly-safe. But two nothrow ops do add up to a nothrow op.Blida

© 2022 - 2024 — McMap. All rights reserved.