C++ 中的 golang 风格 "defer"
golang-style "defer" in C++
我正在阅读 go 语言的 defer 语句。它允许您指定在函数结束时要执行的操作。例如,如果你有一个文件指针或资源,而不是用每个可能的 return 路径写 free/delete,你只需要指定一次延迟函数。
看起来类似的东西最终可能会出现在 C++ 中(, ) Until then, is there anything unforeseen about doing it with an object whose destructor makes a callback? It looks like the destructor order for local variables is sane 而且它也能很好地处理异常,尽管可能不会在信号出现时退出。
这是一个示例实现...有什么问题吗?
#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";});
}
输出:Hello, world!
这个已经存在了,叫做作用域保护。看看这个精彩的演讲:https://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C。这使您可以轻松创建要在退出时调用的任意可调用对象。这是较新的版本;它最初是在 go 出现之前很久就开发的。
总的来说它工作得很好,但我不确定你说的它处理异常是什么意思。从必须在范围退出时调用的函数中抛出异常是一团糟。原因:当异常被抛出(而不是立即被捕获)时,当前范围退出。所有析构函数都得到 运行,异常将继续传播。如果其中一个析构函数抛出,你会怎么做?您现在有两个实时异常。
我想有一种语言可以尝试处理这个问题,但它非常复杂。在 C++ 中,抛出析构函数很少被认为是一个好主意。
这已经存在于 C++ 中,这是一个非常糟糕的主意,您提供的示例说明了为什么这样做毫无意义,我希望委员会永远不会引入它。
例如,如果你有一个文件句柄,那么写一个 class 来为你做,这样你就不必为每个用例都写一个 defer 语句,你可以很容易地做到这一点忘记做。或者只是简单地弄错了。你写一个析构函数,一次。而已。然后你可以保证 class 的所有使用都是安全的。它更安全,更容易。
Boost 在智能指针编程技术中对此进行讨论:
你可以这样做,例如:
#include <memory>
#include <iostream>
#include <functional>
using namespace std;
using defer = shared_ptr<void>;
int main() {
defer _(nullptr, bind([]{ cout << ", World!"; }));
cout << "Hello";
}
或者,没有 bind
:
#include <memory>
#include <iostream>
using namespace std;
using defer = shared_ptr<void>;
int main() {
defer _(nullptr, [](...){ cout << ", World!"; });
cout << "Hello";
}
您也可以为此推出自己的小型 class,或使用 N3830/P0052:
的参考实现
The C++ Core Guidelines also have a guideline which employs the gsl::finally
function, for which there's an implementation here.
有许多代码库为此采用了类似的解决方案,因此,
有对这个工具的需求。
相关SO讨论:
- Is there a proper 'ownership-in-a-package' for 'handles' available?
- Where's the proper (resource handling) Rule of Zero?
我正在阅读 go 语言的 defer 语句。它允许您指定在函数结束时要执行的操作。例如,如果你有一个文件指针或资源,而不是用每个可能的 return 路径写 free/delete,你只需要指定一次延迟函数。
看起来类似的东西最终可能会出现在 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";});
}
输出:Hello, world!
这个已经存在了,叫做作用域保护。看看这个精彩的演讲:https://channel9.msdn.com/Shows/Going+Deep/C-and-Beyond-2012-Andrei-Alexandrescu-Systematic-Error-Handling-in-C。这使您可以轻松创建要在退出时调用的任意可调用对象。这是较新的版本;它最初是在 go 出现之前很久就开发的。
总的来说它工作得很好,但我不确定你说的它处理异常是什么意思。从必须在范围退出时调用的函数中抛出异常是一团糟。原因:当异常被抛出(而不是立即被捕获)时,当前范围退出。所有析构函数都得到 运行,异常将继续传播。如果其中一个析构函数抛出,你会怎么做?您现在有两个实时异常。
我想有一种语言可以尝试处理这个问题,但它非常复杂。在 C++ 中,抛出析构函数很少被认为是一个好主意。
这已经存在于 C++ 中,这是一个非常糟糕的主意,您提供的示例说明了为什么这样做毫无意义,我希望委员会永远不会引入它。
例如,如果你有一个文件句柄,那么写一个 class 来为你做,这样你就不必为每个用例都写一个 defer 语句,你可以很容易地做到这一点忘记做。或者只是简单地弄错了。你写一个析构函数,一次。而已。然后你可以保证 class 的所有使用都是安全的。它更安全,更容易。
Boost 在智能指针编程技术中对此进行讨论:
你可以这样做,例如:
#include <memory>
#include <iostream>
#include <functional>
using namespace std;
using defer = shared_ptr<void>;
int main() {
defer _(nullptr, bind([]{ cout << ", World!"; }));
cout << "Hello";
}
或者,没有 bind
:
#include <memory>
#include <iostream>
using namespace std;
using defer = shared_ptr<void>;
int main() {
defer _(nullptr, [](...){ cout << ", World!"; });
cout << "Hello";
}
您也可以为此推出自己的小型 class,或使用 N3830/P0052:
的参考实现The C++ Core Guidelines also have a guideline which employs the gsl::finally
function, for which there's an implementation here.
有许多代码库为此采用了类似的解决方案,因此, 有对这个工具的需求。
相关SO讨论:
- Is there a proper 'ownership-in-a-package' for 'handles' available?
- Where's the proper (resource handling) Rule of Zero?