Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

an alternative to finally

48 views
Skip to first unread message

Bonita Montero

unread,
Apr 8, 2019, 9:10:31 AM4/8/19
to
I'd like to have finally with C++, but unfortunately C+ lacks finally.
And RAII is not always an alterantive because writing a class with a
con- and destructor for a purpose only used once is mostly too complex.

So I had the idea of a wrapper-class which calls the ()-operator of
another class on destruction. So here's my solution.

#include <iostream>

using namespace std;

template<typename T>
struct invoke_on_destruct
{
T &t;

invoke_on_destruct( T &t ) :
t( t )
{
}

~invoke_on_destruct()
{
t();
}
};


int main()
{
string str( "hello world" );
auto f = [&str]() { cout << str << endl; };
invoke_on_destruct<decltype(f)> des( f );
return 0;
}

I think that's very handy for emulating finally. Is there already
a class like invoke_on_destruct in the C++ standard-library?

Alf P. Steinbach

unread,
Apr 8, 2019, 9:43:11 AM4/8/19
to
No, but there is ¹one called `final_action` in Microsoft's (!) helper
library for the C++ core guidelines, on GitHub.

It's modelled on Petru Margineans (often referred to as co-author Andrei
Alexandrescu's) ²ScopeGuard class, but without the ScopeGuard dimiss
functionality, and apparently without mentioning ScopeGuard or Marginean.


Cheers!,

- Alf

Links:
¹ <url: https://github.com/Microsoft/GSL/blob/master/include/gsl/gsl_util>
² <url:
http://www.drdobbs.com/cpp/generic-change-the-way-you-write-excepti/184403758>

Öö Tiib

unread,
Apr 9, 2019, 3:17:48 AM4/9/19
to
I've never needed generic scope guards, but can
try something randomly:

#include <iostream>
#include <memory>
#include <string>

// some ugly macros to get unique_ptr useful
#define TP1(X, Y) X ## Y
#define TP2(X, Y) TP1(X, Y)
#define DEFER(CAPTURE,CODE) \
auto TP2(LMB,__LINE__) = [CAPTURE]() CODE; \
std::unique_ptr<decltype(TP2(LMB,__LINE__)), void(*) \
(decltype(TP2(LMB,__LINE__))*)> TP2(DEFERER,__LINE__) \
(&TP2(LMB,__LINE__), [](auto* p) {(*p)();})

// usage
int main ()
{
std::string str( "hello world" );

DEFER(&str,
{
std::cout << str << " 1" << std::endl;
});

std::cout << "doing some stuff\n";

DEFER(&str,
{
std::cout << str << " 2" << std::endl;
});

std::cout << "doing more stuff\n";

return 0;
}

output:
doing some stuff
doing more stuff
hello world 2
hello world 1

Perhaps these macros confuse it more than help.

Juha Nieminen

unread,
Apr 9, 2019, 8:36:08 AM4/9/19
to
Bonita Montero <Bonita....@gmail.com> wrote:
> I think that's very handy for emulating finally. Is there already
> a class like invoke_on_destruct in the C++ standard-library?

This is a really ugly hack, but you can abuse std::unique_ptr for the
same purpose...

int main()
{
std::unique_ptr<void, void(*)(void*)> finally
((void*)1, [](void*) { std::cout << "finally!\n"; });

std::cout << "test\n";
}

Yeah, it's really ugly and cringey, but it works...

Bonita Montero

unread,
Apr 9, 2019, 8:56:41 AM4/9/19
to
The problem is here that you won't have a capture.

Paavo Helde

unread,
Apr 9, 2019, 9:19:02 AM4/9/19
to
Capture is easy to add:

#include <iostream>
#include <functional>
#include <memory>

int main() {
int x = 1;
std::unique_ptr<void, std::function<void(void*)>> finally
((void*)1, [&x](void*) {
std::cout << "finally x is " << x << "\n"; });

std::cout << "test\n";
x = 2;
}


0 new messages