When any allocation of the new container or copying of the elements fails with an exception, will the current contents of the target container remain intact?
CodePudding user response:
The exception safety guarantee do we have when copying a C container is the basic guarantee.
When you copy a container A to a container B, if an exception is thrown, the container B will not remain intact, its status will be partially modified (partially overwritten).
As Eljay says: Exceptions in the midst of copying will leave the original container in a well-defined state (assuming the type it holds are well-behaved types), and the copied into a container in a well-defined (albeit incomplete copy) state.
All C Standard Library code provides (at least) a basic guarantee.
Atomicity or strong guarantee or prevent partial objects created is not mandated by the standard, i think, because strong guarantee can be expensive.
You should copy the contents of a source container into an intermediate container, if there are no problems (no throws), move the contents of the intermediate container into the target container, otherwise, throw away the intermediate container (or something like the copy-and-swap idiom), an example.
Anyway, you can see the assignment operator implementation.
I hope I’ve helped at least a little, even if I’m a beginner.
Edit :
class some_type final {
public:
constexpr some_type() noexcept : data(0) { }
explicit constexpr some_type(const int d) noexcept : data(d) { }
some_type(const some_type& other) : data(other.data) { error(); }
auto& operator=(const some_type& other) {
data = other.data;
error();
return *this;
}
constexpr auto get() const noexcept { return data; }
private:
static unsigned int copy_count;
int data;
void error() { if ( copy_count == 7) throw std::exception(); }
};
unsigned int some_type::copy_count = 0U;
Example 1 :
int main()
{
std::vector src{ some_type(3), some_type(2), some_type(1), some_type(0)}; // 4 copies
std::vector<some_type> dest{ some_type(5) }; // 1 copy (5 copies)
std::cout <<
"\nDest Size : " << dest.size() << // size : 1
"\nDest Capacity : " << dest.capacity() << // capacity : 1
"\nDest Values : ";
for (const auto& value : dest)
std::cout << value.get() << ' '; // values : 5
try {
dest = src; // 4 copies (more than 7 copies, THROW!)
} catch (...) {
std::cout <<
"\n"
"\nDest Size : " << dest.size() << // size : 0
"\nDest Capacity : " << dest.capacity() << // capacity : 4
"\nDest Values : ";
for (const auto& value : dest)
std::cout << value.get() << ' '; // values :
std::cerr << "\n\nUnknown error : Something went wrong\n";
return 1;
}
}
Example 2 :
int main()
{
std::vector src{ some_type(3), some_type(2), some_type(1), some_type(0)}; // 4 copies
std::vector<some_type> dest;
dest.reserve(4);
dest = { some_type(5) }; // 1 copy (5 copies)
std::cout <<
"\nDest Size : " << dest.size() << // size : 1
"\nDest Capacity : " << dest.capacity() << // capacity : 4
"\nDest Values : ";
for (const auto& value : dest)
std::cout << value.get() << ' '; // values : 5
try {
dest = src; // 4 copies (more than 7 copies, THROW!)
} catch (...) {
std::cout <<
"\n"
"\nDest Size : " << dest.size() << // size : 1
"\nDest Capacity : " << dest.capacity() << // capacity : 4
"\nDest Values : ";
for (const auto& value : dest)
std::cout << value.get() << ' '; // values : 3
std::cerr << "\n\nUnknown error : Something went wrong\n";
return 1;
}
}
If you print the dest values you will see that it is partially copied.
CodePudding user response:
I just had an idea: I simply created a vector and did a copy-assignment on it through another vector. The first vector's size was larger than the sencond's before the copy-assignment. But as the capacity was the former size before a atomic implementation coudln't be possible under this circumstance.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<size_t> toBeOverwritten;
toBeOverwritten.resize( 1000, 0 );
vector<size_t> overwriteFrom;
overwriteFrom.resize( 500, 0 );
toBeOverwritten = overwriteFrom;
cout << toBeOverwritten.capacity() << endl;
}