Вопрос

I came across this syntax recently for try-catch for function.

struct A
{
  int a;

  A (int i) : a(i)  // normal syntax
  {
    try {}
    catch(...) {}
  }

  A ()   // something different
  try : a(0) {}
  catch(...) {}

  void foo ()  // normal function
  try {}
  catch(...) {}
};

Both syntax are valid. Is there any technical difference between these syntax apart from coding style ? Is one of the syntax superior to other by any aspect ?

Это было полезно?

Решение

The First Syntax:
The scope of the try block starts after the Member Initialization list has been completed, So any exception thrown during Member Initialization will not be caught by this try-catch block.

The second syntax:
It ensures that if an exception gets thrown during Member Initialization list then you are able to catch the exception.

The Third Syntax:
It ensures that any exception thrown from betwen the starting brace of the try block inside the function body gets caught appropriately, It would mean any exception caused during the argument passing(if any can occur) will not be caught in this try-catch block.

So yes they are disinctly different in what functionality they provide.


EDIT:
Some guidelines to be considered while using the second syntax(function-try-block) in constructors & destructors:

As per the C++ Standard,

If the catch block does not throw (either rethrow the original exception, or throw something new), and control reaches the end of the catch block of a constructor or destructor, then the original exception is automatically rethrown.

In Simple words:
A constructor or destructor function-try-block's handler code MUST finish by emitting some exception.

Guideline 1:
Constructor function-try-block handlers have only one purpose -- to translate an exception. (And maybe to do logging or some other side effects.) They are not useful for any other purpose.

Throwing a exception from destructors is an bad idea, Take a look here to know why.
Guideline 2:
Destructor function-try-blocks have no practical use at all. There should never be anything for them to detect, and even if there were something to detect because of evil code, the handler is not very useful for doing anything about it because it can not suppress the exception.

Guideline 3:
Always clean up unmanaged resource acquisition in local try-block handlers within the constructor or destructor body, never in constructor or destructor function-try-block handlers.


For Standardese Fans:

C++ standard, clause 15.3, paragraph 15:

If a return statement appears in a handler of the function-try-block of a constructor, the program is ill-formed.

C++ standard, clause 15.3, paragraph 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. Otherwise, a function returns when control reaches the end of a handler for the function-try-block (6.6.3). Flowing off the end of a function-try-block is equivalent to a return with no value; this results in undefined behavior in a value-returning function (6.6.3).


References:
Have a look at this must read resource here for more details & explanation.

Другие советы

Function-try-block is useful mostly in constructors, because there is no other way of catching exceptions in initialization list. In destructors one must be careful to return in catch block, because exception will be automatically re-thrown. (And in good design destructors must not throw.) In normal functions this feature is not useful. Edit: an old but still good article: http://drdobbs.com/184401316

Might as well cite the spec... Or at least a draft.

Section 15 (4):

A function-try-block associates a handler-seq with the ctor-initializer, if present, and the compound-statement. An exception thrown during the execution of the compound statement or, for constructors and destructors, during the initialization or destruction, respectively, of the class’s subobjects, transfers control to a handler in a function-try-block in the same way as an exception thrown during the execution of a try-block transfers control to other handlers.

(Here the handler-seq is the stuff after the catch and the compound-statement is the function body.)

So the "function try block" on a constructor or destructor catches exceptions thrown by the ctor-initializers and by the construction or destruction of subobjects.

On a function other than a constructor or destructor, it is the same as simply wrapping the function body. (Well, as far as I can discern from reading the spec.)

Interesting feature, and new to me. Thanks for bringing it up.

The "something different" example puts the processing of the initializer list within the scope of the try block.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top