Souvent, je suis dans une situation où j'ai besoin d'un simple wrapper RAII, mais je ne voudrais pas créer une toute nouvelle classe pour cela pour de nombreuses raisons, notamment des contraintes de temps et des problèmes d'organisation. Ma solution quick-n-dirty est la suivante.
Dites que je veux m'assurer que d'ici la fin de la portée, je veux qu'un booléen revienne à son état d'origine:
bool prevState = currState;
currState = newState;
std::unique_ptr<int, std::function<void(int*)>> txEnder(new int(0), [&prevState](int* p) {
currState = prevState;
delete p;
});
Cette solution fonctionne bien, mais le problème est qu’il est nécessaire d’allouer et de désallouer cet entier pour que unique_ptr
fonctionne et appeler le destructeur personnalisé à la destruction.
Existe-t-il un moyen plus simple de faire cela sans avoir à écrire toute une classe et à se débarrasser de la variable new
pour le modèle factice int
?
Un peu mieux que le vôtre: vous pouvez utiliser &prevState
dans le destructeur personnalisé sans le supprimer. Vous n'avez donc pas besoin de new
et 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;
}
Vous avez également oublié de capturer currState
dans le lambda.
Voici un exemple: https://ideone.com/DH7vZu
Vous pouvez utiliser BOOST_SCOPE_EXIT
auto prevState{currState};
currState = newState;
BOOST_SCOPE_EXIT(&currState, &prevState)
{
currState = prevState;
} BOOST_SCOPE_EXIT_END
Que diriez-vous de gsl::finally
? La bibliothèque n’est pas aussi lourde que boost et finally
n’utilise pas std::function
et peut donc être facilement insérée. Aussi, pas d'allocation dynamique de 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;
}
Exemple en ligne: https://ideone.com/Xi1izz (avec gsl::finally
copié, puisque #include <gsl/gsl>
n'est pas disponible ici)
N'utilisez pas std::function
. Cela crée beaucoup de code, y compris vtables. https://gcc.godbolt.org/z/XgDoHz
Si vous ne souhaitez absolument pas utiliser une classe ou une fonction externe, procédez comme suit:
bool foo_2() {
bool f = false;
auto eos = [&](void*){
f = true;
};
std::unique_ptr<void, decltype(eos)> h{&eos,std::move(eos)};
return f;
}
Si vous êtes d'accord avec une petite fonction réutilisable, ci-dessous fonctionne. Ceci résume le void*
non utilisé.
C++ 14 ou version ultérieure
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;
}