假设我在做一些在抛出异常时需要清理的事情。
例如,假设我正在创建一个动态数组,并且需要构造对象,但是它们的构造函数可能会抛出一个异常:
size_t const n = 100;
T *const p = static_cast<T *>(operator new(sizeof(T) * n));
size_t i;
for (i = 0; i < n; ++i)
new (&p[i]) T(1, 2, 3); // Not exception-safe if T::T(T const &) throws!我可以通过catch (...) { ...; throw; }修复它
size_t const n = 100;
T *const p = static_cast<T *>(operator new(sizeof(T) * n));
size_t i;
try
{
for (i = 0; i < n; ++i)
new (&p[i]) T(1, 2, 3);
}
catch (...)
{
while (i > 0)
p[--i].~T();
operator delete(p);
throw;
}或者通过作用域析构函数。
size_t n = 100;
struct Guard
{
T *p;
size_t i;
Guard(size_t n) : i(), p(static_cast<T *>(operator new(sizeof(T) * n))) { }
~Guard()
{
while (i > 0)
p[--i].~T();
operator delete(p);
}
} guard(n);
for (guard.i = 0; guard.i < n; ++guard.i)
new (&guard.p[guard.i]) T(1, 2, 3);
guard.i = 0; // Successful... "commit" the changes
guard.p = NULL; // or whatever is necessary to commit the changes我应该在什么时候使用哪种技术,为什么?
(注:这个例子只是为了说明两种技术之间的区别。我知道这不是完美的代码,所以请在这个特定的例子中做而不是。(这只是为了说明。)
发布于 2014-03-12 09:57:51
使用析构函数的解决方案优于显式try/catch。
发布于 2014-03-12 10:02:22
总的来说,我认为这是一个规模和安全的问题。
try/catch的问题有两个方面:
catch (不知何故)的早期返回都无法清除try/catch块使代码混乱catch中访问变量,必须在try之前定义变量,从而支持默认构造/空;这可能是痛苦的。相反,延迟语句和卫队不会创建不必要的块/作用域,因此不会产生缩进,而是线性读取。
示例:
char buffer1[sizeof(T)];
try {
new (buffer1) T(original);
char buffer2[sizeof(T)];
try {
new (buffer2) T(original);
// stuff here
} catch(...) {
reinterpret_cast<T*>(buffer2)->~T();
throw;
}
} catch(...) {
reinterpret_cast<T*>(buffer1)->~T();
throw;
}与之相比:
char buffer1[sizeof(T)];
new (buffer1) T(original);
Defer const defer1{[&buffer1]() { reinterpret_cast<T*>(buffer1)->~T(); } };
char buffer2[sizeof(T)];
new (buffer2) T(original);
Defer const defer1{[&buffer2]() { reinterpret_cast<T*>(buffer2)->~T(); } };
// stuff here我要指出的是,把这些概括起来似乎是个好主意:
class Guard {
public:
explicit Guard(std::function<void()> f): _function(std::move(f)) {}
Guard(Guard&&) = delete;
Guard& operator=(Guard&&) = delete;
Guard(Guard const&) = delete;
Guard& operator=(Guard const&) = delete;
~Guard() {
if (not _function) { return; }
try { _function(); } catch(...) {}
}
void cancel() { _function = std::function<void()>{}; }
private:
std::function<void()> _function;
}; // class Guard
class Defer {
public:
explicit Defer(std::function<void()> f): _guard(std::move(f)) {}
private:
Guard _guard;
}; // class Deferhttps://stackoverflow.com/questions/22347089
复制相似问题