I made a working alternative Finally block for C++ exceptions. Opinions welcomed.

Started by
8 comments, last by Tom Sloper 8 years, 7 months ago

At work, I'm used to exceptions with the try-catch-finally format. I wondered how to add 'finally' to C++.

After seeing a finally block wasn't implemented in C++11 (Stroustrup is against them in favor of RAII...), and how others asked for it, I tried this alternative. I think it does the trick without any issue, as finally is used to clean up any resources allocated in the try block. I think it's nice to have. Do you think this alternative is just as effective?

1) Put this at the top of your code: #define finally

2) And, since you can create a unit block using { }, just put finally before that.

Example (poor, but proves a point):


#define finally#include using namespace std;int main(){         int *p = NULL;    try    {        cout << "Allocating..." << endl;        p = new int;    }    catch(bad_alloc e)    {        cout << e.what() << endl;    }    finally {        cout << "Cleaning up!" << endl;        delete p;    }    return 0;}

Output:

Allocating...

Cleaning up!

Advertisement

This doesn't work.

After [p = new int;], put [throw exception("uh oh");] -- the finally block will not run.

It runs for me. I added the throw/catch exception.


#define finally#include using namespace std;int main(){         int *p = NULL;    try    {        cout << "Allocating." << endl;        p = new int;        throw bad_alloc();    }    catch(bad_alloc e)    {        cout << e.what() << endl;    }      catch (exception e)    {        cout << e.what() << endl;    }    finally    {        cout << "Done!" << endl;        if (p) {            delete p;            p = NULL;        }    }    system("pause");    return 0;}

Current Output: Allocating.

bad allocation

Done!

This thread is dumb.

#define wait_no

void is_thread_dumb() {
    try {
        throw std::exception("yes");
    } catch ( const std::exception& ex ) {
        throw ex;
    } wait_no {
        cout << "nope\n";
    }
}

int main() {
    try {
        is_thread_dumb();
    } catch ( const std::exception& ex ) {
        std::cout << ex.what();
    }
}
Output: "yes"


And here I was hoping for some magic C++ trickery. What a disappointment.

What do you think 'finally' does?

This works as an alternative. When I asked for opinions, I didn't expect an immature person calling it 'dumb' or reputation clickers who can't voice an opinion. This site is filled with kids with nothing better to do. Go outside. Learn to socialize and be respectable.

The point is your hack does silently NOT work in some cases, usually, if in some case you would not use RAII, you either only catch what you need, not everything, or you rethrow exceptions after local cleanup.

You don't seem to know how finally works:

See the Java code below.

Your code would not execute the finally. However in Java it will execute the finally.

Finally is always called in Java unless you:

  • Call system.exit()
  • Another thread interrupts this one
  • The JVM crashes

Ofcourse a C++ finally needs to mirror this.



public class Main {
	public static void main(String args[]) {
		something();
	}
	
	public static int something() {
		int success = 1;
		int failure = -1;
		try {  
		    exceptionthrower();  
		    return success;  
		}  
		catch (Exception e) {   
		    return failure;  
		}  
		finally {  
		    System.out.println("Will always be printed");
		}
		System.out.println("Wil never be printed");
	}
	
	public static void exceptionthrower() throws Exception {
		throw new Exception();
	}
}

"Talk is cheap. Show me the code."

- Linus Torvalds

What do you think 'finally' does?

This works as an alternative.

A real finally block *always* executes after the try/catch block.

Yours does not run if a non-caught exception is thrown, and also doesn't run if the catch block re-throws the exception.
Both of these are common occurrences, so your #define finally hack is very misleading -- making it look like you've got a real finally block there, when actually it's just normal post-try/catch code, which does not fulfill the same guarantee as a real finally block...

Yes it was rude for fastcall to call your thread dumb... But it's also extremely immature to refuse to see the flaws in your code, to delete all your posts from the site (as a rule, mods generally restore deleted posts), to take your bat and ball and run home while insulting everyone on the board. Don't complain about professionalism when lowering yourself to an unprofessional level... All I did was point out that your code doesn't work (the same as a real finally keyword).

[edit] Nevermind... Admin tools show you used to have a few accounts here ~10 years ago, which were notorious for leaving the site forever and then coming back a week later, until they got banned for some reason... Good to see you haven't changed.

[edit 2] Actually you have a 2nd account which was last active in January... For future reference, you can just change your display name instead of creating a new account. Let a mod know if you want one of your accounts disabled.

If you really want to have a safe finally implementation (even though I consider it more or less useless due to destructors and RAII as already mentioned), I think you can use c++11 lamdas and use said destructor behaviour:


class Finally
{
public:

    using FinallyFunc = void (*)();
    
    Finally(FinallyFunc finally) : m_finally(finally)
    {
    }
    
    ~Finally(void)
    {
        m_finally();
    }
    
private:
    
    std::function<void ()> m_finally;
};

{
    const Finally finally([] ()
    {  
        std::cout << "Will always be printed";
    });

    try
    {
        throw new std::exception;
    }
    catch(...)
    {
        return;
    }
}

std::cout << "Will never be printed";

I didn't use lamdas myself but I suppose this should work if you call the lamda in the "Finally" destructor. Syntax is a bit strange since you have to put { } around the whole try-catch block and have to place the finally declaration on top. I probably wouldn't use this personally but if you really insist (and have access to c++11).

When I asked for opinions, I didn't expect an immature person calling it 'dumb' or reputation clickers who can't voice an opinion. This site is filled with kids with nothing better to do. Go outside. Learn to socialize and be respectable.


We strive for a higher level of civility on these boards. This thread is closed.

-- Tom Sloper -- sloperama.com

This topic is closed to new replies.

Advertisement