在 C++11(或更新版本)中创建 RAII 包装器而无需编写新的 class 的最短路径是什么?
What's the shortest path in C++11 (or newer) to create an RAII wrapper without having to write a new class?
我经常遇到需要一个简单的 RAII 包装器的情况,但我不想为此创建一个全新的 class,原因有很多,包括时间限制和组织问题。我的快速解决方案如下。
假设我想确保在范围结束时,我想要一个布尔值切换回其原始状态:
bool prevState = currState;
currState = newState;
std::unique_ptr<int, std::function<void(int*)>> txEnder(new int(0), [&prevState](int* p) {
currState = prevState;
delete p;
});
这个解决方案工作正常,但肮脏的部分是分配和释放整数的必要性只是为了使 unique_ptr
工作并在销毁时调用自定义析构函数。
有没有更简洁的方法来做到这一点,而不必写一个完整的 class,并摆脱虚拟 int
的 new
?
您可以使用BOOST_SCOPE_EXIT
auto prevState{currState};
currState = newState;
BOOST_SCOPE_EXIT(&currState, &prevState)
{
currState = prevState;
} BOOST_SCOPE_EXIT_END
比你的好一点点:你可以在自定义析构函数中使用&prevState
而不删除它,所以你不需要new
和delete
一些东西:
void foo(bool & currState, bool newState)
{
bool prevState = currState;
currState = newState;
std::unique_ptr<bool, std::function<void(bool*)>> txEnder(&prevState, [&prevState, &currState](bool* p) {
currState = prevState;
});
cout << "currState: " << currState << endl;
}
您还忘记在 lambda 中捕获 currState
。
这是一个例子:https://ideone.com/DH7vZu
不要使用 std::function
。它创建了很多代码,包括 vtables。 https://gcc.godbolt.org/z/XgDoHz
如果您绝对不想使用任何外部 class 或函数,请执行以下操作:
bool foo_2() {
bool f = false;
auto eos = [&](void*){
f = true;
};
std::unique_ptr<void, decltype(eos)> h{&eos,std::move(eos)};
return f;
}
如果您对一些可重复使用的功能没问题,请执行以下操作。这抽象了未使用的 void*
。
C++14 或更高版本
template<class F>
auto call_at_end_of_scope(F&& f){
auto eos = [f{std::forward<F>(f)}](void*){f();};
return std::unique_ptr<void, decltype(eos)>{&eos,std::move(eos)};
}
bool foo_3() {
bool f = false;
auto handle = call_at_end_of_scope([&](){
f = true;
});
return f;
}
gsl::finally
怎么样?库不像 boost 那么重,并且 finally
不使用 std::function
,因此可以轻松内联。也没有 std::unique_ptr
的动态分配
using namespace std;
void foo(bool & currState, bool newState)
{
auto revertState = gsl::finally([prevState = currState, &currState]{
currState = prevState;
});
currState = newState;
cout << "currState: " << currState << endl;
}
int main() {
bool state = false;
foo(state, true);
cout << "state: " << state << endl;
return 0;
}
在线示例:https://ideone.com/Xi1izz(复制gsl::finally
,因为#include <gsl/gsl>
在这里不可用)
我经常遇到需要一个简单的 RAII 包装器的情况,但我不想为此创建一个全新的 class,原因有很多,包括时间限制和组织问题。我的快速解决方案如下。
假设我想确保在范围结束时,我想要一个布尔值切换回其原始状态:
bool prevState = currState;
currState = newState;
std::unique_ptr<int, std::function<void(int*)>> txEnder(new int(0), [&prevState](int* p) {
currState = prevState;
delete p;
});
这个解决方案工作正常,但肮脏的部分是分配和释放整数的必要性只是为了使 unique_ptr
工作并在销毁时调用自定义析构函数。
有没有更简洁的方法来做到这一点,而不必写一个完整的 class,并摆脱虚拟 int
的 new
?
您可以使用BOOST_SCOPE_EXIT
auto prevState{currState};
currState = newState;
BOOST_SCOPE_EXIT(&currState, &prevState)
{
currState = prevState;
} BOOST_SCOPE_EXIT_END
比你的好一点点:你可以在自定义析构函数中使用&prevState
而不删除它,所以你不需要new
和delete
一些东西:
void foo(bool & currState, bool newState)
{
bool prevState = currState;
currState = newState;
std::unique_ptr<bool, std::function<void(bool*)>> txEnder(&prevState, [&prevState, &currState](bool* p) {
currState = prevState;
});
cout << "currState: " << currState << endl;
}
您还忘记在 lambda 中捕获 currState
。
这是一个例子:https://ideone.com/DH7vZu
不要使用 std::function
。它创建了很多代码,包括 vtables。 https://gcc.godbolt.org/z/XgDoHz
如果您绝对不想使用任何外部 class 或函数,请执行以下操作:
bool foo_2() {
bool f = false;
auto eos = [&](void*){
f = true;
};
std::unique_ptr<void, decltype(eos)> h{&eos,std::move(eos)};
return f;
}
如果您对一些可重复使用的功能没问题,请执行以下操作。这抽象了未使用的 void*
。
C++14 或更高版本
template<class F>
auto call_at_end_of_scope(F&& f){
auto eos = [f{std::forward<F>(f)}](void*){f();};
return std::unique_ptr<void, decltype(eos)>{&eos,std::move(eos)};
}
bool foo_3() {
bool f = false;
auto handle = call_at_end_of_scope([&](){
f = true;
});
return f;
}
gsl::finally
怎么样?库不像 boost 那么重,并且 finally
不使用 std::function
,因此可以轻松内联。也没有 std::unique_ptr
using namespace std;
void foo(bool & currState, bool newState)
{
auto revertState = gsl::finally([prevState = currState, &currState]{
currState = prevState;
});
currState = newState;
cout << "currState: " << currState << endl;
}
int main() {
bool state = false;
foo(state, true);
cout << "state: " << state << endl;
return 0;
}
在线示例:https://ideone.com/Xi1izz(复制gsl::finally
,因为#include <gsl/gsl>
在这里不可用)