我的经验表明,scoped_guard 的使用远不如您可以手写的任何可重复使用的简短 RAII 类。
在尝试scoped_guard 之前,我已经编写了 RAII 类来
- 绘制形状后,将 GLcolor 或 GLwidth 设置回原来的值
- 确保文件在我拥有
fopened 后拥有fclosed。
- 在执行慢速函数期间将鼠标指针更改为齿轮/沙漏后,将鼠标指针重置为其初始状态
- 将 QListView 的
sorting 状态重置为之前的状态,一旦我暂时完成了对其 QListViewItems 的更改——我不希望列表在每次更改单个项目的文本时重新排序...
使用简单的 RAII 类
以下是我的代码与我手工制作的 RAII 类的样子:
class scoped_width {
int m_old_width;
public:
scoped_width(int w) {
m_old_width = getGLwidth();
setGLwidth(w);
}
~scoped_width() {
setGLwidth(m_old_width);
}
};
void DrawTriangle(Tria *t)
{
// GLwidth=1 here
auto guard = scoped_width(2); // sets GLwidth=2
draw_line(t->a, t->b);
draw_line(t->b, t->c);
draw_line(t->c, t->a);
setGLwidth(5);
draw_point(t->a);
draw_point(t->b);
draw_point(t->c);
} // scoped_width sets GLwidth back to 1 here
scoped_width 的实现非常简单,而且可重复使用。
从消费者方面来看也非常简单易读。
使用scoped_guard (C++14)
现在,使用scoped_guard,我必须捕获介绍器 ([]) 中的现有值,以便将其传递给守卫的回调:
void DrawTriangle(Tria *t)
{
// GLwidth=1 here
auto guard = sg::make_scoped_guard([w=getGLwidth()](){ setGLwidth(w); }); // capture current GLwidth in order to set it back
setGLwidth(2); // sets GLwidth=2
draw_line(t->a, t->b);
draw_line(t->b, t->c);
draw_line(t->c, t->a);
setGLwidth(5);
draw_point(t->a);
draw_point(t->b);
draw_point(t->c);
} // scoped_guard sets GLwidth back to 1 here
以上内容甚至不适用于 C++11。
更不用说尝试以这种方式将状态引入 lambda 会伤害我的眼睛。
使用scoped_guard (C++11)
在 C++11 中你必须这样做:
void DrawTriangle(Tria *t)
{
// GLwidth=1 here
int previous_width = getGLwidth(); // explicitly capture current width
auto guard = sg::make_scoped_guard([=](){ setGLwidth(previous_width); }); // pass it to lambda in order to set it back
setGLwidth(2); // sets GLwidth=2
draw_line(t->a, t->b);
draw_line(t->b, t->c);
draw_line(t->c, t->a);
setGLwidth(5);
draw_point(t->a);
draw_point(t->b);
draw_point(t->c);
} // scoped_guard sets GLwidth back to 1 here
如你所见,
-
scoped_guard snoppet 要求
- 3 行保留以前的值(状态)并将其设置为新值,并且
- 2 个堆栈变量(
previous_width 和 guard,同样)保持之前的状态
-
手工制作的RAII class需要
- 1 可读行设置新状态并保留前一个状态,并且
- 1 个堆栈变量 (
guard) 用于保存之前的状态。
结论
我认为这样的例子
void some_function() {
sg::scoped_guard([](){ cout << "this is printed last"; }
cout << "this is printed first";
}
无法证明scoped_guard 的有用性。
我希望有人能告诉我为什么我没有从scoped_guard 获得预期收益。
我相信通过编写简短的手工类可以更好地利用 RAII,而不是使用更通用但难以使用的 scoped_guard