wake-up-neo.com

Was ist der kürzeste Pfad in C++ 11 (oder neuer), um einen RAII-Wrapper zu erstellen, ohne eine neue Klasse schreiben zu müssen?

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?

10

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

6
mch

Sie können BOOST_SCOPE_EXIT verwenden.

auto prevState{currState};
currState = newState;
BOOST_SCOPE_EXIT(&currState, &prevState)
{
     currState = prevState;
} BOOST_SCOPE_EXIT_END
7
VTT

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)

0
R2RT

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;
}
0
balki