Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ember.js/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ ScopeGuard的使用真的会带来更好的代码吗?_C++_Raii_Scopeguard - Fatal编程技术网

C++ ScopeGuard的使用真的会带来更好的代码吗?

C++ ScopeGuard的使用真的会带来更好的代码吗?,c++,raii,scopeguard,C++,Raii,Scopeguard,许多年前,我遇到了AndreiAlexandrescu和PetruMarginean编写的一个实用程序类ScopeGuard,它介绍并讨论了一个名为ScopeGuard的实用程序类,用于编写异常安全代码。我想知道使用这些对象进行编码是否真的会产生更好的代码,或者它是否会混淆错误处理,因为可能警卫的回调会更好地显示在catch块中?有人有在实际生产代码中使用这些的经验吗?它肯定会改进您的代码。您的临时性的声明,它是晦涩的,代码从代码>块中得到的好处在C++中是不正确的,因为RAII是一个已建立的习

许多年前,我遇到了AndreiAlexandrescu和PetruMarginean编写的一个实用程序类ScopeGuard,它介绍并讨论了一个名为ScopeGuard的实用程序类,用于编写异常安全代码。我想知道使用这些对象进行编码是否真的会产生更好的代码,或者它是否会混淆错误处理,因为可能警卫的回调会更好地显示在catch块中?有人有在实际生产代码中使用这些的经验吗?

它肯定会改进您的代码。您的临时性的声明,它是晦涩的,代码从<<代码> catch >代码>块中得到的好处在C++中是不正确的,因为RAII是一个已建立的习惯用法。C++中的资源处理是通过资源获取完成的,垃圾回收是通过隐式析构函数调用完成的。 另一方面,显式的
catch
块会使代码膨胀并引入微妙的错误,因为代码流变得更加复杂,必须显式地处理资源


RAII(包括<代码> StopeGueGue/Cuff>)不是C++中的一种晦涩难懂的技术,而是牢固地建立了最佳实践。

< P>我没有使用这个特定的模板,但我以前使用过类似的东西。是的,与以不同方式实现的同样健壮的代码相比,它确实会带来更清晰的代码。

我经常使用它来保护内存使用,即从操作系统返回的需要释放的东西。例如:

DATA_BLOB blobIn, blobOut;
blobIn.pbData=const_cast<BYTE*>(data);
blobIn.cbData=length;

CryptUnprotectData(&blobIn, NULL, NULL, NULL, NULL, CRYPTPROTECT_UI_FORBIDDEN, &blobOut);
Guard guardBlob=guardFn(::LocalFree, blobOut.pbData);
// do stuff with blobOut.pbData
DATA\u BLOB blobIn,blobOut;
pbData=const_cast(数据);
blobIn.cbData=长度;
CryptUnprotectData(&blobIn,NULL,NULL,NULL,NULL,CRYPTPROTECT\u UI\u probled,&bloout);
Guard guardBlob=guardFn(::LocalFree,blobOut.pbData);
//使用blobOut.pbData做一些事情

<>如果有一块C++代码,我可以建议每个C++程序员花10分钟学习,它是ScopeGuard(现在是免费提供的一部分)。 我决定尝试将ScopeGuard的一个(稍加修改)版本用于我正在开发的一个小型Win32 GUI程序。您可能知道Win32有许多不同类型的资源需要以不同的方式关闭(例如,内核句柄通常使用
CloseHandle()
关闭,GDI
BeginPaint()
需要与
EndPaint()
配对等)。我将ScopeGuard与所有这些资源一起使用,还可使用
分配工作缓冲区(例如,用于与Unicode之间的字符集转换)


让我惊讶的是程序的长度缩短了很多。基本上,这是一个双赢的结果:您的代码同时变得更短、更健壮。未来的代码更改不会泄露任何信息。他们就是不能。这有多酷?

我不得不说,不,不,不。这里的答案有助于说明为什么这是一个真正糟糕的想法。资源处理应该通过可重用类来完成。他们通过使用scope guard实现的唯一一件事就是干掉wazoo,并在整个代码库中复制他们的资源释放代码,而不是编写一个类来处理资源,然后就这样,整个代码库


如果范围保护有任何实际用途,那么资源处理就不是其中之一。在这种情况下,它们大大低于普通RAII,因为RAII是重复数据消除和自动的,范围保护是手动代码复制或半身像。

我认为上述答案缺少一个重要的注意事项。正如其他人所指出的,您可以使用
ScopeGuard
来释放分配的资源,而不受故障(异常)的影响。但这可能不是您使用scope guard的唯一目的。事实上,链接文章中的示例将
ScopeGuard
用于不同的目的:转换。简而言之,如果有多个对象(即使这些对象正确地使用了RAII)需要保持某种相关状态,那么它可能会很有用。如果这些对象中任何一个的状态改变导致异常(我认为,这通常意味着它的状态没有改变),那么所有已经应用的更改都需要回滚。这就产生了它自己的一系列问题(如果回滚也失败了怎么办?)。您可以尝试推出自己的类来管理此类相关对象,但随着这些对象数量的增加,它会变得混乱,您可能会退回到内部使用
ScopeGuard

是的

<>这在C++中是非常重要的,甚至在d:

中也有一个特殊的语法。
void somefunction() {
    writeln("function enter");
    // c++ has similar constructs but not in syntax level
    scope(exit) writeln("function exit");

    // do what ever you do, you never miss the function exit output
}

我的经验表明,
scoped_-guard
的使用远远不如手工编写的任何短期可重用RAII类

在尝试
作用域保护
之前,我已经将RAII类编写到

  • 绘制形状后,将GLcolor或GLwidth设置回原始值
  • 确保在我打开文件后,该文件已
    fclose
    d
  • 在执行慢速函数期间将鼠标指针更改为gears/Hourglass后,将鼠标指针重置为其初始状态
  • 一旦我临时完成更改其
    QListViewItems
    ,将QListView的
    排序
    状态重置回以前的状态--我不希望每次更改单个项目的文本时列表都重新排序
使用简单的RAII类 以下是我手工制作的RAII类的代码外观:

类范围的\u宽度{
int m_old_宽度;
公众:
作用域宽度(int w){
m_old_width=getGLwidth();
设置宽度(w);
}
~scoped_width(){
setGLwidth(m_old_width);
}
};
空心三角形(三角形三角形)
{
//此处的GLwidth=1
auto guard=scoped_width(2);//设置GLwidth=2
画线(t->a,t->b);
画线(t->b,t->c);
画线(t->c,t->a);
设置宽度(5);
绘制点(t->a);
绘制点(t->b);
绘制点(t->c);
}//作用域\u width在此处将GLwidth设置回1
非常简单的
作用域宽度的实现
,并且非常可重用。 非常简单易读
void some_function() {
    sg::scoped_guard([](){ cout << "this is printed last"; }

    cout << "this is printed first";
}