首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >RAII州管理

RAII州管理
EN

Stack Overflow用户
提问于 2016-03-10 08:37:27
回答 5查看 527关注 0票数 4

我需要改变一个状态。那就做点什么。然后将状态重新设置为原来的状态-例如:

代码语言:javascript
复制
auto oldActivationOrder = mdiArea->activationOrder();
mdiArea->setActivationOrder( QMdiArea::StackingOrder );
mdiArea->cascadeSubWindows();
mdiArea->setActivationOrder( oldActivationOrder );

我该怎么用RAII的方式做这件事?(c++ 11和/或14)

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

有几个建议用于创建用于处理状态更改的自定义类(BoBTFish、mindriot、Mattias )。这个解决方案似乎是好的和明确的。但是,我认为这是一个缺点,因为它将行数从4增加到20+。如果经常使用,这会使代码膨胀。另外,似乎有些地方由于有一个单独的类而丢失了。

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

sp2danny建议一个可以重用的广义状态更改类。这避免了代码膨胀,前提是它可以替换几个自定义类。我将接受这个答案--但我想正确的方法确实取决于上下文。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2016-03-10 10:00:11

您可以执行一个通用模板:

代码语言:javascript
复制
template< typename Obj, typename Getter, typename Setter , typename StateType >
class ScopedStateChangeType
{
public:
    ScopedStateChangeType( Obj& o, Getter g, Setter s, const StateType& state )
        : o(o), s(s)
    {
        oldstate = (o.*g)();
        (o.*s)(state);
    }
    Obj* operator -> () { return &o; }
    ~ScopedStateChangeType()
    {
        (o.*s)(oldstate);
    }

private:
    Obj& o;
    Setter s;
    StateType oldstate;
};

template< typename Obj, typename Getter, typename Setter , typename StateType >
auto MakeScopedStateChanger( Obj& o, Getter g, Setter s, StateType state )
     -> ScopedStateChangeType<Obj,Getter,Setter,StateType>
{
    return { o, g, s, state };
}

用它就像:

代码语言:javascript
复制
QMdiArea mdiArea;

{
    auto ref = MakeScopedStateChanger(
        mdiArea, &QMdiArea::activationOrder, &QMdiArea::setActivationOrder,
        QMdiArea::StackingOrder );
    ref->cascadeSubWindows();
}

如果你经常使用这个模式,也许这是值得的。

票数 1
EN

Stack Overflow用户

发布于 2016-03-10 08:46:15

Initialisation.:Resource Acquisition Is

这也意味着资源发布就是破坏,尽管我从未见过人们谈论RRID,尽管RRID更有用。(或许这应该是终止,还是终结?)

重点是,在对象的构造函数中做一些工作,并在析构函数中有效地将其反转。这意味着无论您如何退出范围,都要执行清理:多个return,多个break,抛出一个异常,.(甚至goto!)

代码语言:javascript
复制
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

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

票数 7
EN

Stack Overflow用户

发布于 2016-03-10 08:56:24

也许实现作用域保护模式的最简洁的方法(尽管可能不是最易读的)是使用使用自定义删除器

代码语言:javascript
复制
#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);
}  
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/35911317

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档