Oft bin ich in einer Situation, in der ich einen einfachen RAII-Wrapper benötige. Ich möchte jedoch aus vielen Gründen keine völlig neue Klasse erstellen, einschließlich Zeitbeschränkungen und Organisationsproblemen. Meine schnelle und schmutzige Lösung ist die folgende.
Angenommen, ich möchte sicherstellen, dass am Ende des Gültigkeitsbereichs ein Boolean in den ursprünglichen Zustand zurückversetzt wird:
bool prevState = currState;
currState = newState;
std::unique_ptr<int, std::function<void(int*)>> txEnder(new int(0), [&prevState](int* p) {
currState = prevState;
delete p;
});
Diese Lösung funktioniert einwandfrei, aber der schmutzige Teil ist die Notwendigkeit, diese Ganzzahl zuzuweisen und freizugeben, damit unique_ptr
funktioniert und der benutzerdefinierte Destruktor bei der Zerstörung aufgerufen wird.
Gibt es einen saubereren Weg, dies zu tun, ohne eine ganze Klasse schreiben zu müssen und die new
für das Dummy int
loszuwerden?
Ein bisschen besser als deins: Sie können &prevState
im benutzerdefinierten Destruktor verwenden, ohne ihn zu löschen. Sie brauchen also nicht new
und delete
etwas:
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;
}
Sie haben auch vergessen, currState
im Lambda zu erfassen.
Hier ist ein Beispiel: https://ideone.com/DH7vZu
Sie können BOOST_SCOPE_EXIT
verwenden.
auto prevState{currState};
currState = newState;
BOOST_SCOPE_EXIT(&currState, &prevState)
{
currState = prevState;
} BOOST_SCOPE_EXIT_END
Wie wäre es mit gsl::finally
? Die Bibliothek ist nicht so umfangreich wie boost und finally
verwendet std::function
nicht, daher kann sie leicht eingebettet werden. Auch keine dynamische Zuordnung von 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;
}
Online-Beispiel: https://ideone.com/Xi1izz (mit kopiertem gsl::finally
, da #include <gsl/gsl>
hier nicht verfügbar ist)
Verwenden Sie nicht std::function
. Es erstellt eine Menge Code, einschließlich vtables. https://gcc.godbolt.org/z/XgDoHz
Wenn Sie absolut keine externe Klasse oder Funktion verwenden möchten, führen Sie folgende Schritte aus:
bool foo_2() {
bool f = false;
auto eos = [&](void*){
f = true;
};
std::unique_ptr<void, decltype(eos)> h{&eos,std::move(eos)};
return f;
}
Wenn Sie mit einer kleinen wiederverwendbaren Funktion zufrieden sind, funktioniert unten. Dies abstrahiert den nicht verwendeten void*
.
C++ 14 oder höher
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;
}