...
The copy assignment operator is flawed because it fails to provide any exception safety guarantee. The function deallocates array
and assigns the element counter, nelems
, before allocating a new block of memory for the copy. As a result, when the new expression throws an exception, the function will have modified the state of both member variables in a way that violates the implicit invariants of the class. Consequently, the object of the class is in an indeterminate state and any operation on it, including its destruction, results in undefined behavior.
Code Block | ||||
---|---|---|---|---|
| ||||
class IntArray { int *array; std::size_t nelems; public: // ... ~IntArray() { delete[] array; } IntArray& operator=(const IntArray &rhs) { if (this != &rhs) { delete[] array; nelems = rhs.nelems; array = new int[nelems]; std::memcpy(array, rhs.array, nelems * sizeof *array); } return *this; } // ... }; |
...
In the compliant solution below, the copy assignment operator provides the Strong Exception Safety guarantee. The function takes care to allocate new storage for the copy before changing the state of the object. Only after the allocation succeeds does the function proceed to change the state of the object. In addition, by copying the array to the newly allocated storage before deallocating the existing array the function avoids the test for self-assignment, thus improving the performance of the code in the common case.
Code Block | ||||
---|---|---|---|---|
| ||||
class IntArray { int *array; std::size_t nelems; public: // ... ~IntArray() { delete[] array; } IntArray& operator=(const IntArray &rhs) { int* const tmp = new int[rhs.nelems]; std::memcpy(tmp, rhs.array, nelems * sizeof *array); delete[] array; array = tmp; nelems = rhs.nelems; return *this; } // ... }; |
...