- Are STL container elements required to have
noexcept
copy-constructors and copy-assignment operators? Please provide a reference if possible. - If not, what is the state of a STL container when an exception happens during a multi-insert, e.g. during fill insert.
The problem comes up when trying to write a generic wrapper that allows intercepting/vetoing modifications. Any implementation I can come up with is likely to change the semantics of the underlying container unless specialized for every container type (which is not really an option).
For example, std::vector
has a fill insert:
void insert (iterator position, size_type n, const value_type& val);
This requires value_type
to be both CopyInsertable as well as CopyAssignable. Note that it does not require the value type to be DefaultConstructible.
Edit 3 Stroustrup himself (table on page 956) indicates that multi-element insert is supposed to have the strong guarantee for all of vector, deque, list and map. Meaning that the full standard library operation either succeeds or fails atomically.
Edit 4 However, the guarantee only applies when relevant operations (in this case the copy constructor) do not themselves throw exceptions, which is exactly my problem.
As far as I understand it, this leaves two basic implementation methods:
- Create dummy entries for the new elements and copy-assign
val
. This only works when it is possible to create dummy elements by either copying existing elements in the container or whenvalue_type
is DefaultConstructible (which is not a requirement). - Copy-construct elements one after the other directly into their respective locations in the container. This seems to be more or less the canonical implementation.
Edit 2: I won't call this undefined behaviour, because that term seems to red flag people into thinking undefined as by language runtime/the standard.
Both implementations seem to leave the container with unknown contents (i.e. it is not clear what elements the container holds after the exception) when either the copy constructor or the copy-assignment operator raise an exception.
Edit 1: Note that this does not mean I assume there is bad behaviour wrt to C++ runtime, e.g. memory leaks or undefined values. However, it seems it is more or less unspecified what the contents of the container are. In particular, the contents of the container could have been completely (albeit consistently) altered.
As an example, consider a third (hybrid) method:
- create a list of
n
copies of the template objectval
. - copy-assign the elements from this list into the target container.
The difference is the effect on the container when the copy constructor raises an exception. In this case, the contents of the container remain unchanged if the copy-constructor throws (but still cause unspecified contents when the copy assignment operator throws). When using pointers (i.e. when not using std::vector
), the copy-assignment can probably be left out and only the pointers re-arranged, making the operation atomic wrt. exceptions.
As for noexcept
on container elements: Objects are created via allocator_traits<value_type>::construct(ptr, args)
, which isn't noexcept
and I also cannot find the requirement that container elements most have a noexcept
copy constructor/copy-assigment operator (e.g. std::shared_ptr
and std::unique_ptr
require this).
Note that automatically generated operations for copy-construct and copy-assign are required to be noexcept
unless they are required to call an operation that itself could raise an exception.
This leaves me confused and I'm sure I missed something, but I cannot figure out the part of the standard that might prove me wrong.