在C++中golang风格的"延迟"

dav*_*agp 10 c++ destructor functional-programming go c++11

我正在阅读关于go语言的推迟陈述.它允许您指定函数结束时要执行的操作.例如,如果您有文件指针或资源,而不是使用每个可能的返回路径写入free/delete,则只需指定defer函数一次.

它看起来像一个模拟可能最终来到C++(什么是C++标准延迟/终结执行?,会不会有范围后卫/范围退出成语的标准化?)之前,有什么意外讲的是一个对象,它这样做析构函数进行回调?它看起来像局部变量析构函数顺序是理智的,它也可以很好地处理异常,但可能不会退出信号.

这是一个示例实现......有什么令人不安的吗?

#include <iostream>
#include <functional>
using namespace std;

class FrameExitTask {
    std::function<void()> func_;
public:
    FrameExitTask(std::function<void()> func) :
    func_(func) {
    }
    ~FrameExitTask() {
        func_();
    }
    FrameExitTask& operator=(const FrameExitTask&) = delete;
    FrameExitTask(const FrameExitTask&) = delete;
};

int main() {
    FrameExitTask outer_task([](){cout << "world!";});
    FrameExitTask inner_task([](){cout << "Hello, ";});
    if (1+1 == 2)
        return -1;
    FrameExitTask skipped_task([](){cout << "Blam";});
}
Run Code Online (Sandbox Code Playgroud)

输出: Hello, world!

pep*_*ico 16

Boost在智能指针编程技术中讨论了这个问题:

你可以做,例如:

#include <memory>
#include <iostream>
#include <functional>

using namespace std;
using defer = shared_ptr<void>;    

int main() {
    defer _(nullptr, bind([]{ cout << ", World!"; }));
    cout << "Hello";
}
Run Code Online (Sandbox Code Playgroud)

或者,没有bind:

#include <memory>
#include <iostream>

using namespace std;
using defer = shared_ptr<void>;    

int main() {
    defer _(nullptr, [](...){ cout << ", World!"; });
    cout << "Hello";
}
Run Code Online (Sandbox Code Playgroud)

您也可以为此推出自己的小类,或者使用N3830/P0052的参考实现:

C++核心指南有一个使用该gsl::finally功能的指南,这里有一个实现.

有许多代码库为此采用类似的解决方案,因此,需要使用此工具.

相关的SO讨论:


Nir*_*man 7

这已经存在,它被称为范围保护。看到这个精彩的演讲:https : //channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C。这使您可以轻松创建在退出时调用的任意可调用对象。这是较新的版本;它最初是在 go 出现之前很久就被开发出来的。

它在一般情况下完美运行,但我不确定你所说的处理异常是什么意思。从必须在作用域退出时调用的函数抛出异常是一团糟。原因:当抛出异常(而不是立即捕获)时,当前作用域退出。所有析构函数都会运行,异常将继续传播。如果其中一个析构函数抛出异常,你会怎么做?您现在有两个实时异常。

我想有一种语言可以尝试处理这个问题,但它非常复杂。在 C++ 中,抛出析构函数被认为是一个好主意是非常罕见的。