During some implementation I stuck with the problem about exception safety guarantee and using std::move()
. I know that SO is not a good place to ask "what is your opinion" (class template Boo
) kind of a question but here I would like to make sure if my understanding is correct and after you read this question maybe you can direct me to the right path.
Consider following code:
struct Foo {
using Y = std::vector<std::string>;
using X = std::vector<Y>;
void add (Y y) {
src.push_back (std::move (y)); // (1)
src = process (std::move (src)); // (2)
}
private:
X process (X&& vec) { // (F)
for (auto& v : vec) {
v.resize (10); // (3)
}
return std::move (vec);
}
X src;
};
Take a look at the add()
member function, if an exception is thrown from (1) and according to the n4296 [vector.modifiers/1]
If an exception is thrown while inserting a single element at the end and
T
isCopyInsertable
oris_nothrow_move_constructible<T>::value
istrue
, there are no effects.
then strong guarantee is preserved, am I right?
If we look at the (2) then exception can also be thrown here, because (3) can throw an exception. Correct me if I am wrong: In this situation (2) if I move src
to the process()
member function and exception is thrown from process()
then src
is unspecified and that means that only basic guarantee is preserved?
To make add()
member function strong guarantee should I change (2) and (F) respectively to:
src = process (src); // (2)
X process (X vec); // (F)
?
So if Foo::src
has huge number of elements, then making strong guarantee is associated with less efficiency (because extra copy has to be made) ?
Maybe guarantee level should be left to decide by the user of the class, by making it a class template, similar to this:
struct S {};
struct B {};
template <typename T>
struct Boo {
using Y = std::vector<std::string>;
using X = std::vector<Y>;
void add (Y y) {
src.push_back (std::move (y));
src = process_helper (typename std::is_same<T, S>::type {});
}
private:
X process_helper (std::true_type) {
return process (src);
}
X process_helper (std::false_type) {
return process (std::move (src));
}
X process (X vec) {
for (auto& v : vec) {
v.resize (10);
}
return std::move (vec);
}
X src;
};
Is it a good or bad idea?
Aucun commentaire:
Enregistrer un commentaire