RAII国家管理

Jak*_*sen 4 c++ raii c++11 c++14

我需要改变一个州.然后做的事情.然后将状态重置回原来的状态 - 例如:

auto oldActivationOrder = mdiArea->activationOrder();
mdiArea->setActivationOrder( QMdiArea::StackingOrder );
mdiArea->cascadeSubWindows();
mdiArea->setActivationOrder( oldActivationOrder );
Run Code Online (Sandbox Code Playgroud)

我如何以RAII方式执行此操作?(c ++ 11和/或14)

编辑:谢谢你的所有答案.

有几个建议可以创建一个用于处理状态更改的自定义类(BoBTFish,mindriot,Mattias Johansson).这个解决方案似乎很清楚.但是我认为这是一个缺点,它将行数从4增加到20+.如果使用了很多,这将使代码膨胀.也似乎有一个单独的类丢失了一些地方.

Ami Tavory建议使用std :: unique_ptr.这没有代码膨胀问题并维护局部性.但是,正如Ami所指出的那样,它可能不是最易读的解决方案.

sp2danny建议可以重用的通用状态更改类.这可以避免代码膨胀,前提是它可以替换多个自定义类.我将接受这个答案 - 但我认为正确的方法实际上取决于背景.

BoB*_*ish 7

RAII:[R esource 一个 cquisition 小号 nitialisation.

这也暗示资源释放是毁灭性的,虽然我从未见过人们谈论RRID,尽管这是更有用的一面.(也许那应该是终止,还是终结?)

关键是,你在一个对象的构造函数中做了一些工作,并在析构函数中有效地反转它.这意味着无论你如何退出范围,都会执行清理:多个returns,多个breaks,抛出异常,......(甚至goto!)

class ScopedActivationOrderChange {
    QMdiArea&             area_;     // the object to operate on
    QMdiArea::WindowOrder oldOrder_; // save the old state

  public:
    ScopedActivationOrderChange(QMdiArea& area, ActivationOrder newOrder)
        : area_(area)
        , oldOrder_(area_.activationOrder()) // save old state
    {
        area_.setActivationOrder(newOrder); // set new state
    }

    ~ScopedActivationOrderChange()
    {
        area_.setActivationOrder(oldOrder_); // reset to old state
    }
};

// ...

{ // <-- new scope, just to establish lifetime of the change
    ScopedActivationOrderChange orderChange{*mdiArea, QMdiArea::StackingOrder};
    mdiArea->cascadeSubWindows();
} // <-- end of scope, change is reversed
Run Code Online (Sandbox Code Playgroud)

标准图书馆没有为此提供任何一般设施.它确实提供了一些用于更具体的用途,例如std::unique_ptr删除动态分配的对象,在某些情况下可以用于其他事情,尽管它有点难看.std::vector可以看作是动态数组的RAII类,也提供了一些其他管理工具,但是这个很容易被滥用于其他目的.


Ami*_*ory 6

实现范围保护模式的最简洁方式(尽管可能不是最可读)也许是使用std::unique_ptr自定义删除器:

#include <memory>
#include <utility>


int main()
{
    void *p, *q;                                                                                                                                                                                         
    auto reverser = [&p, &q](char *){std::swap(p, q);};
    /* This guard doesn't really release memory - 
        it just calls the lambda at exit. */
    auto guard = std::unique_ptr<char, decltype(reverser)>{nullptr, reverser};
    std::swap(p, q);
}  
Run Code Online (Sandbox Code Playgroud)