在一些实现过程中,我遇到了关于异常安全保证和使用std::move()
. 我知道 SO 不是问“你的意见是什么”(类模板Boo
)这类问题的好地方,但在这里我想确定我的理解是否正确,在你阅读了这个问题之后,也许你可以指导我正确的道路。
考虑以下代码:
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;
};
看一下add()
成员函数,如果从(1)中抛出异常并根据n4296 [vector.modifiers/1]
如果在末尾插入单个元素时抛出异常
T
isCopyInsertable
或is_nothrow_move_constructible<T>::value
istrue
,则没有效果。
那么强保证被保留了,对吗?
如果我们看(2)那么这里也可以抛出异常,因为(3)可以抛出异常。如果我错了,请纠正我:在这种情况下(2),如果我移动src
到成员函数并且从那时process()
抛出异常是未指定的,这意味着只保留基本保证?process()
src
为了使add()
成员函数得到强有力的保证,我应该将(2)和(F)分别更改为:
src = process (src); // (2)
X process (X vec); // (F)
?
那么如果Foo::src
元素数量巨大,那么做强保证会降低效率(因为必须制作额外的副本)?
也许保证级别应该由类的用户决定,通过使其成为类模板,类似于:
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;
};
这是个好主意还是坏主意?