protected override void onpaint没有执行_如何在C++中延迟执行

3d6cd74edb6778d2cdb7375abd87daad.png

图片来自网络,与内容无关

场景

在编程中,错误处理是经常遇到的。而在遇到错误时,恢复已处理数据或释放已分配资源也是不可避免的。而经常使用的方法无非几种,1)在每个错误处理的返回前处理;2)goto到最后统一处理再返回;3)抛出异常在catch中处理。几种方法,都有各自的优点和缺点。对比如下

cd0859a1ebba91214aff9b4debe0e565.png

实现

可见,几种常见方法各有优劣。那有没有一种使用方法,没有明显缺点的方法呢?这个在Golang中有一个方法:defer。Defer指定的语句或函数,会在超出其所在作用域(多数用于函数返回时)执行,可以做些清理收尾工作。

那在C++中能不能实现这样功能呢?答案是肯定的。RAII的理念,就是很好的。把收尾的工作,当作是资源的释放,让这一切在开始的时候就保证发生。基于这个理论,可以这样做:

void fun(bool doit){// something to initalize;std::shared_ptr defer(nullptr, [](void*){// uninitalize or recovery;});if (!doit){return;}// 其他的一些处理return;}

像这样,我们就有机会在defer的deleter中去做一些我们希望的事情。一般来说,从实现目的上来说我们可以这样做,但是从代码质量上来说,这并不是好的代码,在大家的共识中,std::shared_ptr是进行资源管理的,当某一天再次看到这段代码或其他没有这方面认知的程序员看到这段代码,可能就觉得莫名其妙了。

从提高代码质量的角度,我们可以创建defer类来做这件事情。这个defer类大约像这个样子

class defer{using OnDestructorAction = std::function;public:defer(OnDestructorAction action) : OnDestructor(action) {}~defer() { OnDestructor(); }protected:OnDestructorAction OnDestructor;};

刚才的函数使用这个类,可以这样改

void fun(bool doit){// something to initalize;defer clean([](){// uninitalize or recovery;});if (!doit){return;}// 其他的一些处理return;}

现在,当我们再次看到时候,就会知道,这里是延时操作(defer),要清理什么(clean)东东,并且任何有C++经验的程序员看到defer的实现都能知道这段代码的工作原理。

但这里依然存在问题,可能会这样创建一个对象 defer clean2(clean); 此时,指定的函数将会被执行两次——clean析构时候执行一次,clean2析构的时候又执行一次——大多时候这不是我们期望的。我们需要禁止defer对象被复制——禁用拷贝构造函数和赋值。完成后如下

class defer{using OnDestructorAction = std::function;public:defer(defer&) = delete;defer(OnDestructorAction action) : OnDestructor(action) {}~defer() { OnDestructor(); }defer operator=(defer&) = delete;protected:OnDestructorAction OnDestructor;};

这样,当有人试图复制对象时将不被允许。这个简单的类又完善了一步。但是,作为一个辅助延时执行的类,不是应该被创建在堆上的——因为这样此对象本身就需要被手动管理——我们自己可以不这样使用,但是不能保证团队中每个人都能正确使用。所以不希望对他操作的,就要声明禁止操作。如何禁止在堆上创建对象呢?当然是new一个了。更改后,大约像这个样子

class defer{using OnDestructorAction = std::function;public:defer(defer&) = delete;defer(OnDestructorAction action) : OnDestructor(action) {}~defer() { OnDestructor(); }defer operator=(defer&) = delete;void* operator new(size_t) = delete;protected:OnDestructorAction OnDestructor;};

通过重载并显式地删除new操作符,现在我们将不能使用new在堆上创建此对象。当new defer时,将得到编译器给出的"error C2280:尝试引用已删除的函数"的错误提示。

到现在,这个类已经能保证在大多数情况下被以正确的方法使用了。然而,依然可以通过别的方法在堆上创建此类的对象,但我却无能为力:

defer* pdefer = (defer*)malloc(sizeof(defer));pdefer->defer::defer([]() {});

当然,如果有人非要以这种方式来创建,那我会认为他是故意的。

至此,实现了类似golang的defer功能!来一段简单但完整的测试程序

#include #include class defer{using OnDestructorAction = std::function;public:defer(defer&) = delete;defer(OnDestructorAction action) : OnDestructor(action) {}~defer() { OnDestructor(); }defer operator=(defer&) = delete;void* operator new(size_t) = delete;protected:OnDestructorAction OnDestructor;};void fun(bool doit){defer clean([](){std::cout << "clean" << std::endl;});if (!doit){std::cout << "! doit" << std::endl;return;}defer clean2([](){std::cout << "clean 2" << std::endl;});std::cout << "doit" << std::endl;return;}int main(){std::cout << "fun(false)" << std::endl;fun(false);std::cout << "func(true)" << std::endl;fun(true);return 0;}

执行以上程序,将得到如下输出

fun(false)! doitcleanfunc(true)doitclean 2clean

原创文章,转载请保留出处 https://www.toutiao.com/i6894983289799606787/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值