Click here to Skip to main content
15,884,298 members
Articles / Programming Languages / C++11
Tip/Trick

"finally" clause in C++

Rate me:
Please Sign up or sign in to vote.
4.87/5 (6 votes)
15 Oct 2012CPOL2 min read 51.7K   10   10
finally like clause in C++

Introduction

This article aims to help a programmer who has the need to use "finally" like clause (like in Java) in C++.

Background

There are many cases where such need for finally clause arises, mostly as I can see it, it always happen when a programmer uses a third party or legacy "C oriented" library that deals with resources in a procedural way like open/close file or connect/disconnect a service.

For example, MFC library solves the problem with the introduction of wrapper classes like CWaitCursor, where the cursor is a resource reclaimed back on destruction of the object. The destruction of the object is deterministic and happens on the event of getting out of scope (block end).

What I'm going to show is a solution for an already existing code that needs to be more deterministic and clean, but yet written in a procedural way.

Another reason to use this "finally" like construct is for external resources that should be reclaimed no matter what happened after they were successfully claimed. For example, deterministic log-out of a remote service no matter what happens after a successful log-in to that service. That way prevents the remote dangling service from waiting for a log-out until some time-out routine will close the remote socket...

This solution is not a replacement for a superior design like using RAII (Resource Acquisition Is Initialization), see "Why doesn't C++ provide a "finally" construct?".

For beginners, I strongly suggest to read briefly the following items in the C++ reference:

  1. Lambda Functions in C++11 - the Definitive Guide
  2. Function objects
  3. std::function
  4. std::bind

It is possible to use the example ahead without deep knowledge of what is lambda or what is function object.

Using the Code

The code will run only on C++11 compiler and maybe some C++0x compilers!

For Beginners

It is very easy to use:

C++
FILE *file = fopen("test","w");

finally close_the_file([&]{
    cout << "Finally you close the file." << endl;
    fclose(file);
});

The [&] {...} is the code I suspect is not well understood for beginners, but it doesn't matter, as long as you accept the "unreadable" set of brackets, everything should be OK.

Let's explain:

  1. Opening a file the C way using stdio library, this is an old way of using files, but it is used here for the sake of the explanation. I consider the file opening as successful!
  2. Next line, there is a declaration of object named close_the_file of a class finally and then there is lambda expression that should run on the event of exiting the scope. basically you can copy and paste the class finally (see ahead) and put somewhere in one of your libraries headers for later use.

The "finally" Class

The finally class provides a means of running commands upon leaving the block by using the destructor of the class.

C++
class finally
{
    std::function<void(void)> functor;
public:
    finally(const std::function<void(void)> &functor) : functor(functor) {}
    ~finally()
    {
        functor();
    }
};

Example

Somehow the example file hasn't been uploaded so I decided to write a little example just to show how it works. Try this:

C++
try {
    cout << "Open a file" << endl;
    FILE *file = fopen("test","w");

    finally close_the_file([&]{
        cout << "Finally you close the file." << endl;
        fclose(file);
    });

    cout << "do something before exception" << endl;

    throw("Some exception");

    cout << "do something after exception!?" << endl;
}
catch(char *ex)
{
    cout << ex << endl;
}
catch(...)
{
    ; //do nothing
}

History

  1. First revision
  2. Alternative example to the example file

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralMy vote of 5 Pin
Shmuel Zang21-Jul-21 21:39
Shmuel Zang21-Jul-21 21:39 
SuggestionBrilliant Idea! Thanks! Pin
Member 1057449910-Jan-15 9:55
Member 1057449910-Jan-15 9:55 
This is a great idea! Saves me. This http://www.stroustrup.com/bs_faq2.html#finally[^] topic in the C++ FAQ is a bug. Without finally C++ is not much use.

The complication with the solution is the syntax and the wording. Finally is really a "later on" concept(as in it would logically be at the end of the code block), so I invented a macro called "REMEMBER_TO" but you can call it what you want. The guarded parts can be really big so its probably better to use a remember_to than a finally which might confuse when reading the code. A better convention might be lowercase so it looks like a regular statement. Or maybe it should just be called "later".

#define _DO_TOKEN_COMBINE__(X,Y) X##Y  // helper macro
#define _TOKEN_COMBINE__(X,Y) _DO_TOKEN_COMBINE__(X,Y)

// Use any of these, the example uses REMEMBER_TO but I think I will start using "later" or "defer".
#define REMEMBER_TO(...) finally _TOKEN_COMBINE__(__make_finally,__LINE__) ([&]{ __VA_ARGS__ ; })  
#define remember_to(...) finally _TOKEN_COMBINE__(__make_finally,__LINE__) ([&]{ __VA_ARGS__ ; })  
#define later(...) finally _TOKEN_COMBINE__(__make_finally,__LINE__) ([&]{ __VA_ARGS__ ; })  
#define defer(...) finally _TOKEN_COMBINE__(__make_finally,__LINE__) ([&]{ __VA_ARGS__ ; })  


  {
    FILE *file = fopen("test","w");
    REMEMBER_TO( fclose(file) );
    std::cout << "Do stuff with the file, it will be cleaned up at the end of the block!" << std::endl;
  }
  {
    CRITICAL_SECTION MyLock;


    EnterCriticalSection(&MyLock);
    REMEMBER_TO( LeaveCriticalSection(&MyLock) );

    std::cout << "This code is guarded by the critical section and will be handled later" << std::endl;
    MyGlobalCounter++;

  }
// If you need to put variable declarations or loops or other statements in the finally clause
// then you can do this by just adding braces in the macro...

    EnterCriticalSection(&MyLock);
    REMEMBER_TO({
       // Do stuff here like a normal block
       for (int x = 0; x < 100; x++)
         std::cout << x << std::endl;
       LeaveCriticalSection(&MyLock);
    });

GeneralMy vote of 5 Pin
magicpapacy22-Oct-12 16:27
magicpapacy22-Oct-12 16:27 
GeneralMy vote of 4 Pin
kosmoh16-Oct-12 7:09
kosmoh16-Oct-12 7:09 
GeneralRe: My vote of 4 Pin
Cpp For All16-Oct-12 21:06
Cpp For All16-Oct-12 21:06 
GeneralRe: My vote of 4 Pin
kosmoh17-Oct-12 6:53
kosmoh17-Oct-12 6:53 
Questionfinally? Pin
Selvin15-Oct-12 15:11
Selvin15-Oct-12 15:11 
AnswerRe: finally? Pin
Cpp For All15-Oct-12 20:09
Cpp For All15-Oct-12 20:09 
GeneralRe: finally? Pin
Selvin15-Oct-12 21:50
Selvin15-Oct-12 21:50 
GeneralRe: finally? Pin
Cpp For All15-Oct-12 23:11
Cpp For All15-Oct-12 23:11 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.