Can You Really Have a Function/Method Without a Body But Just a Try/Catch Block

Can you really have a function/method without a body but just a try/catch block?

Yes, it is standard. Function try blocks, as they're called, aren't that much use for regular functions, but for constructors, they allow you to catch exceptions thrown in the initialiser list.

Note that, in the constructor case, the exception will always be rethrown at the end of any catch blocks.

try\catch block in the main() function without brackets

Your construction is a function-try-block and is defined in drafs n4296 for C++ 11 specification at 8.4 Function definitions [dcl.fct.def.general] with:

Function definitions have the form

  • function-definition:

    • attribute-specifier-seqopt decl-specifier-seqopt declarator virt-specifier-seqopt function-body
  • function-body:

    • ctor-initializeropt compound-statement
    • function-try-block
    • = default ;
    • = delete ;

and later in 15 Exception handling [except] with:

function-try-block:

  • try ctor-initializeropt compound-statement handler-seq

Examples suggest that the normal usage for a function-try-block should be a ctor, but it is valid for a normal function (and main is syntactically a mere function)

It is valid and works normally, meaning that catch block is only evaluated if an exception occurs in the ctor-initializeropt on in the compound-statement. You can confirm it in your code by adding prints in your blocks or by testing return value.

In a Unix like system

foo
echo $?

should echo 0

In a Windows system under a CMD.exe windows

foo.exe
if errorlevel 1 echo "Catch block"

should not output Catch block

If your debugger lets you execute instructions in the catch block... it is not C++ 11 conformant!

But it is known that when exiting a block, MSVC debugger puts cursor on last line of block, I assume that is is what is happening here because the last line of the function-try-block is last line of catch.

Try catch block outside the main() scope

This is called a Function-try-block

A function-try-block associates a sequence of catch clauses with the
entire function body, and with the member initializer list (if used in
a constructor) as well. Every exception thrown from any statement in
the function body, or (for constructors) from any member or base
constructor, or (for destructors) from any member or base destructor,
transfers control to the handler-sequence the same way an exception
thrown in a regular try block would.

Use a 'try-finally' block without a 'catch' block

You would use it to ensure some actions occur after the try content or on an exception, but when you don't wish to consume that exception.

Just to be clear, this doesn't hide exceptions. The finally block is run before the exception is propagated up the call stack.

You would also inadvertently use it when you use the using keyword, because this compiles into a try-finally (not an exact conversion, but for argument's sake it is close enough).

try
{
TrySomeCodeThatMightException();
}
finally
{
CleanupEvenOnFailure();
}

Code running in finally is not guaranteed to run, however the case where it isn't guaranteed is fairly edge - I can't even remember it. All I remember is, if you are in that case, chances are very good that not running the finally isn't your biggest problem :-) so basically don't sweat it.

Update from Tobias: finally will not run if the process is killed.

Update from Paddy: Conditions when finally does not execute in a .net try..finally block

The most prevalent example you may see is disposing of a database connection or external resource even if the code fails:

using (var conn = new SqlConnection("")) // Ignore the fact we likely use ORM ;-)
{
// Do stuff.
}

Compiles into something like:

SqlConnection conn;

try
{
conn = new SqlConnection("");
// Do stuff.
}
finally
{
if (conn != null)
conn.Dispose();
}

Try / Catch block substituted for a method block in a destructor

This is a function try block and it's completely legal.

See, for example, here.

The only time that you can do something in a function try block that you can't do in a normal try block in a function is catch exceptions thrown by expression in a constructor initializer list (and even then you end up having to throw something), but that doesn't apply here.

This GOTW #66 is particularly interesting, although it concentrates more on constructors. It contains this "moral":

Since destructors should never emit an exception, destructor function-try-blocks have no practical use at all.

Just to add clarification, the code as written will cause any exception caught to be rethrown due to ISO/IEC 14882:2003 15.3 [except.handle] / 16:

The exception being handled is rethrown if control reaches the end of a handler of the function-try-block of a constructor or destructor. [...]

However it is legal to have a parameterless return in the handler of a function try block for a destructor - it is only forbidden in a function try block for a constructor - and this will supress the rethrow of the exception. So either of these alternatives would prevent the exception from leaving the destructor.

File::~File()
try
{
Clear();
}
catch (...)
{
Log("caught exception");
return;
}

File::~File()
{
try
{
Clear();
}
catch (...)
{
Log("caught exception");
}
}

Why should I not wrap every block in try-catch?

A method should only catch an exception when it can handle it in some sensible way.

Otherwise, pass it on up, in the hope that a method higher up the call stack can make sense of it.

As others have noted, it is good practice to have an unhandled exception handler (with logging) at the highest level of the call stack to ensure that any fatal errors are logged.

iphone - try, catch question

You can certainly have multiple lines in your try block. Example:

@try {
if (managedObjectContext == nil) {
actionMessage = @"accessing user recipe library";
[self initCoreDataStack];
}
actionMessage = @"finding recipes";
recipes = [self recipesMatchingSearchParameters];
actionMessage = @"generating recipe summaries";
summaries = [self summariesFromRecipes:recipes];
}
@catch (NSException *exception) {
NSMutableDictionary *errorDict = [NSMutableDictionary dictionary];
[errorDict setObject:[NSString stringWithFormat:@"Error %@: %@", actionMessage, [exception reason]] forKey:OSAScriptErrorMessage];
[errorDict setObject:[NSNumber numberWithInt:errOSAGeneralError] forKey:OSAScriptErrorNumber];
*errorInfo = errorDict;
return input;
} @catch (OtherException * e) {
....
} @finally {
// Any clean up can happen here.
// Finally will be called if an exception is thrown or not.
}

And a link to practical use of exceptions:

https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/Exceptions/Tasks/HandlingExceptions.html

When is a function try block useful?

You use it in constructors to catch errors from initializers. Usually, you don't catch those errors, so this is a quite exceptional use.

Otherwise, it is useless: unless I'm proven wrong,

void f() try { ... } catch (...) { ... }

is strictly equivalent to

void f() { try { ... } catch (...) { ... } }

try/catch blocks with async/await

Alternatives

An alternative to this:

async function main() {
try {
var quote = await getQuote();
console.log(quote);
} catch (error) {
console.error(error);
}
}

would be something like this, using promises explicitly:

function main() {
getQuote().then((quote) => {
console.log(quote);
}).catch((error) => {
console.error(error);
});
}

or something like this, using continuation passing style:

function main() {
getQuote((error, quote) => {
if (error) {
console.error(error);
} else {
console.log(quote);
}
});
}

Original example

What your original code does is suspend the execution and wait for the promise returned by getQuote() to settle. It then continues the execution and writes the returned value to var quote and then prints it if the promise was resolved, or throws an exception and runs the catch block that prints the error if the promise was rejected.

You can do the same thing using the Promise API directly like in the second example.

Performance

Now, for the performance. Let's test it!

I just wrote this code - f1() gives 1 as a return value, f2() throws 1 as an exception:

function f1() {
return 1;
}

function f2() {
throw 1;
}

Now let's call the same code million times, first with f1():

var sum = 0;
for (var i = 0; i < 1e6; i++) {
try {
sum += f1();
} catch (e) {
sum += e;
}
}
console.log(sum);

And then let's change f1() to f2():

var sum = 0;
for (var i = 0; i < 1e6; i++) {
try {
sum += f2();
} catch (e) {
sum += e;
}
}
console.log(sum);

This is the result I got for f1:

$ time node throw-test.js 
1000000

real 0m0.073s
user 0m0.070s
sys 0m0.004s

This is what I got for f2:

$ time node throw-test.js 
1000000

real 0m0.632s
user 0m0.629s
sys 0m0.004s

It seems that you can do something like 2 million throws a second in one single-threaded process. If you're doing more than that then you may need to worry about it.

Summary

I wouldn't worry about things like that in Node. If things like that get used a lot then it will get optimized eventually by the V8 or SpiderMonkey or Chakra teams and everyone will follow - it's not like it's not optimized as a principle, it's just not a problem.

Even if it isn't optimized then I'd still argue that if you're maxing out your CPU in Node then you should probably write your number crunching in C - that's what the native addons are for, among other things. Or maybe things like node.native would be better suited for the job than Node.js.

I'm wondering what would be a use case that needs throwing so many exceptions. Usually throwing an exception instead of returning a value is, well, an exception.



Related Topics



Leave a reply



Submit