我需要改变一个状态。那就做点什么。然后将状态重新设置为原来的状态-例如:
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建议一个可以重用的广义状态更改类。这避免了代码膨胀,前提是它可以替换几个自定义类。我将接受这个答案--但我想正确的方法确实取决于上下文。
发布于 2016-03-10 10:00:11
您可以执行一个通用模板:
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 };
}用它就像:
QMdiArea mdiArea;
{
auto ref = MakeScopedStateChanger(
mdiArea, &QMdiArea::activationOrder, &QMdiArea::setActivationOrder,
QMdiArea::StackingOrder );
ref->cascadeSubWindows();
}如果你经常使用这个模式,也许这是值得的。
发布于 2016-03-10 08:46:15
Initialisation.:Resource Acquisition Is
这也意味着资源发布就是破坏,尽管我从未见过人们谈论RRID,尽管RRID更有用。(或许这应该是终止,还是终结?)
重点是,在对象的构造函数中做一些工作,并在析构函数中有效地将其反转。这意味着无论您如何退出范围,都要执行清理:多个return,多个break,抛出一个异常,.(甚至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标准库没有为此提供任何通用工具。它确实提供了一些更具体的用途,比如删除动态分配对象的std::unique_ptr,在某些情况下,这些对象可以用于其他事情,尽管它有点难看。std::vector可以被看作是动态数组的RAII类,也提供了一些其他管理工具,但是这个类不太容易被用于其他目的。
发布于 2016-03-10 08:56:24
也许实现作用域保护模式的最简洁的方法(尽管可能不是最易读的)是使用使用自定义删除器。
#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);
} https://stackoverflow.com/questions/35911317
复制相似问题