According to cppreference.com, std::vector::emplace() offers the strong exception guarantee unconditionally:
If an exception is thrown (e.g. by the constructor), the container is left unmodified, as if this function was never called (strong exception guarantee).
However, this doesn't seem to be the case in practice with GCC 7.1.1. The following program:
#include <iostream>
#include <vector>
struct ugly
{
int i;
ugly(int i) : i{i} { }
ugly(const ugly& other) = default;
ugly& operator=(ugly&& other) {
if (other.i == 3) {
throw other.i;
}
i = other.i;
return *this;
}
ugly& operator=(const ugly& other) = default;
};
int main() {
std::vector<ugly> vec;
vec.reserve(6);
vec.emplace_back(0);
vec.emplace_back(1);
vec.emplace_back(2);
vec.emplace_back(4);
vec.emplace_back(5);
try {
vec.emplace(vec.begin() + 3, 3);
} catch (int i) {
}
for (const auto& u : vec) {
std::cout << u.i << "\n";
}
return 0;
}
prints
0 1 2 4 4 5
In fact, I have a hard time seeing how emplace() could possibly provide the strong guarantee if copying/moving is allowed to throw. To emplace in the middle, we have to move a bunch of elements out of the way first, then construct the new element in its place. If any of that throws, we'd have to move all the other elements back where they were, but those moves can throw too!
So who's wrong, cppreference or gcc?
emplace_back
and (sorry, correction) is followed by additional restrictions. – Officialdom