Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/124.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++ 在C+;中不使用括号类的原因是什么+;?_C++_Raii - Fatal编程技术网

C++ 在C+;中不使用括号类的原因是什么+;?

C++ 在C+;中不使用括号类的原因是什么+;?,c++,raii,C++,Raii,通常需要完成以下任务:更改某事物的状态,执行操作,然后将状态更改回原始状态。例如,在Win32 GDI中,需要更改背景颜色,然后进行一些绘制,然后重新更改颜色 可以直接执行以下操作: COLORREF oldColor = SetBkColor( deviceContext, newColor ); drawStuff( deviceContext ); SetBkColor( deviceContext, oldColor ); 或者通过一个括号类,在构造函数中进行正向更改,在析构函数中进行

通常需要完成以下任务:更改某事物的状态,执行操作,然后将状态更改回原始状态。例如,在Win32 GDI中,需要更改背景颜色,然后进行一些绘制,然后重新更改颜色

可以直接执行以下操作:

COLORREF oldColor = SetBkColor( deviceContext, newColor );
drawStuff( deviceContext );
SetBkColor( deviceContext, oldColor );
或者通过一个括号类,在构造函数中进行正向更改,在析构函数中进行反向更改:

CBkColorSwitcher switcher( deviceContext, newColor );
drawStuff( deviceContext );
//once control reaches end of block the switcher is destroyed and the change is reverted

括号类的优点是显而易见的——如果在两次更改之间抛出异常,则会正确地恢复更改。有什么缺点?

< P>我认为这是最好的练习。我看不出有什么缺点(除了可读性)?

< P>这实际上是一个众所周知的和广泛使用的C++习惯用法。Win32 API是C API,它们的实现模式不同。如果您在C++中编程,最好使用RAII语言来处理资源分配和分配,通过在C API上编写薄包装器,或者更好地重用现有的、设计良好的C++替换。Java程序员可以将RAII视为finally子句的替代品。

一个缺点是,您通常必须定义一个新类,这往往会有一点开销

除此之外,这是(另一个)非常常见的RAII示例,通常是一个非常好的方法


编辑:如果您没有编写一个类,而只是编写了一个函数,那么您可以使用它在退出作用域时执行任意代码块。不过,我认为对于大多数应用程序来说,它可能有点太可爱了

有两个缺点,您需要编写更多的代码,最终会创建更多的对象。 你无法控制它的使用。如果使用不当,你就会失去好处。e、 g

CBkColorSwitcher * switcher = new CBkColorSwitcher(......)

也就是说,我认为优点远远大于缺点,我更喜欢括号类方法。我看到的缺点是(至少在您给出的示例中):

  • 除非代码的读者理解方括号类的责任,否则就不太清楚您实际在做什么
  • 创建括号类的成本
  • 编写代码来实现方括号类将比没有方括号类的版本花费更长的时间

话虽如此,使用RAII是做到这一点的“正确”方法,其好处远远大于缺点。

我在这里挑剔,但是:

  • 代码大小,由于异常处理程序,您的代码将更大
  • 您需要编写大量的类来处理所有类型的开关
  • 更大的堆栈
  • 始终在所有异常上预执行代码,即使不需要(例如,您只是希望应用程序崩溃)

  • 在编写C++包装时所付出的额外努力在较少的错误代码和更容易出错的代码中得到了回报。我不同意编写更多代码。更多的牙套,是的。但是在最终的代码中,设置/恢复行的数量减少了2倍,这通常不是更多的代码。如果您必须多次执行相同的操作,那么能够重用该类可以节省代码。它还确保在引发异常时恢复更改。如果没有它,您将不得不编写一个try/catch来恢复到初始状态。@Glen:jalf指出您断言的更多代码是错误的。为一个具有构造函数/析构函数的类添加6行。然后每次使用减去1行。因此,只要使用6次或6次以上,就不需要额外的代码。@Glen:不正确地使用某些东西总是会失去任何优势。就像忘记成对使用C函数一样。所以这不是真正的原因。注意:像这样使用新工具总是错误的(安全例外)。在现代C++中,指针总是被封装在智能指针中,你是指使用SyrdypTR的RAII属性吗?你能详细说明一下吗?看看链接<代码>共享\u ptr可以使用自定义删除器。通过执行任意函数,您可以(ab)使用它(或者绑定)来“删除”一个空指针。离开块作用域时,将调用自定义删除程序alternative@Phil纳什:我同意,我是想找一个例子来反驳“写一个新类是相当大的开销”首先想到的是点和
    shared_ptr
    滥用。使用自定义deleter的
    shared_ptr
    通常被用作这样管理句柄的方法。要执行任意代码,
    ScopeGuard
    确实是一个更合适的选项。哪个异常处理程序?堆栈大小非常小。没有状态的对象通常只需要一个字节。@jalf我说的是编译器插入的代码,无论发生什么情况都可以调用dtor。至于你的其他评论,正如我说的,我在挑剔,不管怎样,我不知道你是如何想出一个没有状态的对象只需要一个字节。从技术上讲,一个对象应该有一个地址,即使它的大小是0字节,但是如果没有人需要它的地址,编译器可以(也会这样做)不执行任何为其分配存储的指令,只在“对象”将被销毁的点调用析构函数(甚至为析构函数添加内联代码)。在C/C++中,根据各自规范中“对象”的定义,对象的大小不能为0字节。也就是说,对于无类型T,
    sizeof(T)
    可以是0。当然,如果没有人以任何直接或间接的方式观察到这个大小,编译器可以按照Charles所描述的那样进行优化。实际上,所有我知道的C++编译器都会将一个典型的无状态范围保护类优化成一对构造函数和析构函数调用(并且通常也将它们内联)。java程序员可以把最后一个子句看作是一个技术性的KLUKE来模仿更优雅的RAII技术的效果。最后,将责任从设计师转移到用户身上,这将导致用户需要的更多潜在错误