Throwing an object of a class defined within a class - c++

I'm reading chapter 16 so that I may begin my assignments for my C++ class. This section is on exception handling. I understand the concept behind a try / catch construct, however, one of the examples in the book is a bit confusing to me. I'm hoping for some explanation as to how this is working. The sample code is below:
// Includes, header guards, and namespace std...
class IntRange
{
private:
int intput;
int lower;
int upper;
public:
// Exception class
class OutOfRange { }; // This is exactly how it appears in the text.
IntRange(int low, int high) { lower = low; upper = high; }
int GetInput()
{
cin >> input;
if (input < lower || input > upper)
throw OutOfRange(); // <-- This is my question in particular. What is this?
return input;
}
};
// End header guard.
// Program entry point.
int main()
{
IntRange range(5, 10)
int userValue;
cout << "Enter a value in the range 5 - 10: ";
try
{
userValue = range.getInput();
cout << "You entered " << userValue << endl;
}
catch (IntRange::OutOfRange) // <-- Again, what is this delcaration and how can
// this data type be defined when IntRange does not
// have a default constructor?
{
cout << "That value is out of range.\n";
}
return 0;
}
The code is exactly as it appears in the textbook, except I put some stuff on the same line in order to keep the question from becomming really long.
If you notice any errors, it's most likely a typo, but the most important points have been double-checked.

throw OutOfRange();
This creates a new instance of class OutOfRange and throws it. Remember that you can also create an instance like this:
my_method( MyClass() );
instead of:
MyClass obj;
my_method( obj );
Now:
catch (IntRange::OutOfRange)
OutOfRange is an inner or nested class of IntRange. See here

throw OutOfRange(); // <-- This is my question in particular. What is this?
This default constructs an object of OutOfRange then throws it.
Even if you do not define a methods in a class the compiler will automatically generate a couple for you one of these is the default constructor. Thus even if you don't specify a constructor there will be one there (Do a google on rule 3/5 for explanation of what methods are generated by the compiler).
catch (IntRange::OutOfRange) // <-- Again, what is this delcaration and how can
// this data type be defined when IntRange does not
// have a default constructor?
Here we are catching an object of type IntRange::OutOfRange. Note: we are not catching an object of IntRange. We are catching the class OutOfRange that happens to be defined inside the class IntRange (apart from where it is defined there is no other relationship).
Also note: Unless you disable it the compiler will automatically generate a copy constructor for all classes. Thus exceptions are usually copy constructed from the throw point to the catch point (its a tiny bit more complex). So your exception object must be copyable.
Also note it is best to catch exceptions by const reference:
catch (IntRange::OutOfRange const& e)
The avoids problems associated with slicing objects that are part of exception hierarchies.

They are creating a custom exception (as a class) called OutOfRange and throwing it.
This way, you can specifically catch an OutOfRange exception, this way:
try
{
//do something
}
catch (OutOfRange o)
{
//you know the input was out of range
}
catch (Exception e)
{
//something else went wrong
}

your OutOfRange class belongs to the IntRange class as a whole - it doesn't belong to any particular object of that class.
In order to use OutOfRange there's no requirement even for IntRange to actually be usable as a concrete class , since IntRange::OutOfRange simply specifies the fully-qualified typename and not an object.
in C++, type names are only important at compile time; data type information (along with variable names and all sorts of other stuff like that in your code) is generally stripped out in its entirety by the compiler - data types only exist to help you write code and to do your debugging.

Related

Throw object vs throw variable as exception in c++ oop [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 months ago.
Improve this question
I have been reading a book where the object oriented implementation for exceptions is as follows:
Rectangle.hpp
class Rectangle
{
private:
// code
public:
class NegativeSize
{
// empty class declaration
// for exception
};
// code
};
Whenever a specific error occurs, the NegativeSize() is thrown from the constructor as follows:
Rectangle.cpp
void Rectangle::setX(int _x)
{
if (_x < 0)
{
// this instantiates an object
throw NegativeSize();
}
x = _x;
}
main.cpp
try
{
// code
}
catch (Rectangle::NegativeSize)
{
cout << "Negative value entered" << endl;
}
But I can do the same thing by declaring a public variable in Rectangle class and throw it instead:
Rectangle.hpp
class Rectangle
{
private:
// code
public:
string NegativeVal;
// code
};
Rectangle.cpp
void Rectangle::setX(int _x)
{
if (_x < 0)
{
throw NegativeSize;
}
x = _x;
}
main.cpp
try
{
// code
}
catch (string NegativeSize)
{
cout << "Negative value entered" << endl;
}
Can the second implementation be considered a good practice?
The actual exception object that the catch clause will catch is not the object that you name or refer to in the throw expression. Instead the exception object is an object of the same (decayed) type as the throw operand and initialized from the same.
So in your first example you throw an object of type Rectangle::NegativeSize which is initialized from NegativeSize() and in the second example you throw a std::string which is a copy of the NegativeSize member, whatever value it holds at that time.
In the second example catch (Rectangle::NegativeSize) will not work, because NegativeSize is not a type anymore. You will need to catch std::string instead, which of course is a problem, since it doesn't tell you at all what the kind of exception this is (plus some other deeper issues).
Throwing a std::string instead of a specific exception class is therefore not a good practice. You wouldn't be able to differentiate different exceptions and catch only those you can handle in a given catch clause.
Throwing a data member also seems pointless. What value will you set it to? Probably just the "Negative value entered" string? If so, that could be thrown directly as throw std::string("Negative value entered"); as well. As I said above, the exception object is going to be a copy anyway. At the catch clause you can't identify anymore that the throw expression used the NegativeSize member.
Also, in practice exception classes are usually derived from std::exception or a class derived from it and are not empty. They commonly store a string which can be given at the point of the throw expression, so that detailed information from the source of the exception can be provided to the user, e.g.:
class Rectangle
{
private:
// code
public:
struct NegativeSize : std::invalid_argument {};
// code
};
//...
void Rectangle::setX(int _x)
{
if (_x < 0)
{
throw NegativeSize("Negative value entered");
}
x = _x;
}
//...
try
{
// code
}
catch (const Rectangle::NegativeSize& e)
{
cout << e.what() << endl;
}
Also, as I do above, exceptions should usually be caught by-reference.

Why doesn't C++ use std::nested_exception to allow throwing from destructor?

The main problem with throwing exceptions from destructor is that in the moment when destructor is called another exception may be "in flight" (std::uncaught_exception() == true) and so it is not obvious what to do in that case. "Overwriting" the old exception with the new one would be the one of the possible ways to handle this situation. But it was decided that std::terminate (or another std::terminate_handler) must be called in such cases.
C++11 introduced nested exceptions feature via std::nested_exception class. This feature could be used to solve the problem described above. The old (uncaught) exception could be just nested into the new exception (or vice versa?) and then that nested exception could be thrown. But this idea was not used. std::terminate is still called in such situation in C++11 and C++14.
So the questions. Was the idea with nested exceptions considered? Are there any problems with it? Isn't the situation going to be changed in the C++17?
There is one use for std::nested exception, and only one use (as far as I have been able to discover).
Having said that, it's fantastic, I use nested exceptions in all my programs and as a result the time spent hunting obscure bugs is almost zero.
This is because nesting exceptions allow you to easily build a fully-annotated call stack which is generated at the point of the error, without any runtime overhead, no need for copious logging during a re-run (which will change the timing anyway), and without polluting program logic with error handling.
for example:
#include <iostream>
#include <exception>
#include <stdexcept>
#include <sstream>
#include <string>
// this function will re-throw the current exception, nested inside a
// new one. If the std::current_exception is derived from logic_error,
// this function will throw a logic_error. Otherwise it will throw a
// runtime_error
// The message of the exception will be composed of the arguments
// context and the variadic arguments args... which may be empty.
// The current exception will be nested inside the new one
// #pre context and args... must support ostream operator <<
template<class Context, class...Args>
void rethrow(Context&& context, Args&&... args)
{
// build an error message
std::ostringstream ss;
ss << context;
auto sep = " : ";
using expand = int[];
void (expand{ 0, ((ss << sep << args), sep = ", ", 0)... });
// figure out what kind of exception is active
try {
std::rethrow_exception(std::current_exception());
}
catch(const std::invalid_argument& e) {
std::throw_with_nested(std::invalid_argument(ss.str()));
}
catch(const std::logic_error& e) {
std::throw_with_nested(std::logic_error(ss.str()));
}
// etc - default to a runtime_error
catch(...) {
std::throw_with_nested(std::runtime_error(ss.str()));
}
}
// unwrap nested exceptions, printing each nested exception to
// std::cerr
void print_exception (const std::exception& e, std::size_t depth = 0) {
std::cerr << "exception: " << std::string(depth, ' ') << e.what() << '\n';
try {
std::rethrow_if_nested(e);
} catch (const std::exception& nested) {
print_exception(nested, depth + 1);
}
}
void really_inner(std::size_t s)
try // function try block
{
if (s > 6) {
throw std::invalid_argument("too long");
}
}
catch(...) {
rethrow(__func__); // rethrow the current exception nested inside a diagnostic
}
void inner(const std::string& s)
try
{
really_inner(s.size());
}
catch(...) {
rethrow(__func__, s); // rethrow the current exception nested inside a diagnostic
}
void outer(const std::string& s)
try
{
auto cpy = s;
cpy.append(s.begin(), s.end());
inner(cpy);
}
catch(...)
{
rethrow(__func__, s); // rethrow the current exception nested inside a diagnostic
}
int main()
{
try {
// program...
outer("xyz");
outer("abcd");
}
catch(std::exception& e)
{
// ... why did my program fail really?
print_exception(e);
}
return 0;
}
expected output:
exception: outer : abcd
exception: inner : abcdabcd
exception: really_inner
exception: too long
Explanation of the expander line for #Xenial:
void (expand{ 0, ((ss << sep << args), sep = ", ", 0)... });
args is a parameter pack. It represents 0 or more arguments (the zero is important).
What we're looking to do is to get the compiler to expand the argument pack for us while writing useful code around it.
Let's take it from outside in:
void(...) - means evaluate something and throw away the result - but do evaluate it.
expand{ ... };
Remembering that expand is a typedef for int[], this means let's evaluate an integer array.
0, (...)...;
means the first integer is zero - remember that in c++ it's illegal to define a zero-length array. What if args... represents 0 parameters? This 0 ensures that the array has at lease one integer in it.
(ss << sep << args), sep = ", ", 0);
uses the comma operator to evaluate a sequence of expressions in order, taking the result of the last one. The expressions are:
s << sep << args - print the separator followed by the current argument to the stream
sep = ", " - then make the separator point to a comma + space
0 - result in the value 0. This is the value that goes in the array.
(xxx params yyy)... - means do this once for each parameter in the parameter pack params
Therefore:
void (expand{ 0, ((ss << sep << args), sep = ", ", 0)... });
means "for every parameter in params, print it to ss after printing the separator. Then update the separator (so that we have a different separator for the first one). Do all this as part of initialising an imaginary array which we will then throw away.
The problem you cite happens when your destructor is being executed as part of the stack unwinding process (when your object was not created as part of stack unwinding)1, and your destructor needs to emit an exception.
So how does that work? You have two exceptions in play. Exception X is the one that's causing the stack to unwind. Exception Y is the one that the destructor wants to throw. nested_exception can only hold one of them.
So maybe you have exception Y contain a nested_exception (or maybe just an exception_ptr). So... how do you deal with that at the catch site?
If you catch Y, and it happens to have some embedded X, how do you get it? Remember: exception_ptr is type-erased; aside from passing it around, the only thing you can do with it is rethrow it. So should people be doing this:
catch(Y &e)
{
if(e.has_nested())
{
try
{
e.rethrow_nested();
}
catch(X &e2)
{
}
}
}
I don't see a lot of people doing that. Especially since there would be an exceedingly large number of possible X-es.
1: Please do not use std::uncaught_exception() == true to detect this case. It is extremely flawed.
Nested exceptions just add most-likely-ignored information about what happened, which is this:
An exception X has been thrown, the stack is being unwound, i.e. destructors of local objects are being called with that exception “in flight”, and the destructor of one of those objects in turn throws an exception Y.
Ordinarily this means that cleanup failed.
And then this is not a failure that can be remedied by reporting it upwards and letting higher level code decide to e.g. use some alternative means to achieve its goal, because the object that held the information necessary to do the clean up has been destroyed, along with its information, but without doing its cleanup. So it's much like an assertion failing. The process state can be very ungood, breaking the assumptions of the code.
Destructors that throw can in principle be useful, e.g. as the idea Andrei once aired about indicating a failed transaction on exit from a block scope. That is, in normal code execution a local object that hasn't been informed of transaction success can throw from its destructor. This only becomes a problem when it clashes with C++'s rule for exception during stack unwinding, where it requires detection of whether the exception can be thrown, which appears to be impossible. Anyway then the destructor is being used just for its automatic call, not in its cleanup rôle. And so one can conclude that the current C++ rules assume the cleanup rôle for destructors.
The real problem is that throwing from destructors is a logical fallacy. It's like defining operator+() to perform multiplication.
Destructors should not be used as hooks for running arbitrary code. Their purpose is to deterministically release resources. By definition, that must not fail. Anything else breaks the assumptions needed to write generic code.
The problem that may happen during stack unwinding with chaining exceptions from destructors is that the nested exception chain may be too long. For example, you have std::vector of 1 000 000 elements each of which throws an exception in its destructor. Let's assume the destructor of std::vector collects all exceptions from destructors of its elements into single chain of nested exceptions. Then resulting exception may be even bigger than original std::vector container. This may cause performance problems and even throwing std::bad_alloc during stack unwinding (that even couldn't be nested because there is not enough memory for doing that) or throwing std::bad_alloc in other unrelated places in the program.

C++ - A few questions about throwing exceptions

I've got a few questions about throwing exceptions in C++.
From what I know about them...
An exception can be thrown from within the main() function. Any block of code that can throw an exception in the main() function should be surrounded by try and catch statements as follows
void foo(//args) {
if (...) {
throw "Error reached";
} ...
int main() {
...
try {
//Code that can throw an excpetion
} catch(const char* msg) (
cerr << msg << endl;
}
...
}
In the example above, why is the argument to the catch a const char *. Doesn't C++ allow for strings? Also, is it possible to throw an exception that isn't a const char *, like an int? or a char?
Does throwing an exception in foo, terminate the foo function?
Are there cases where you could put the try and catch statements in the same function as the throw?
Sorry if these are basic questions.
Thanks SO
why is the argument to the catch a const char *
Because you threw string literal which decays to const char*. In short, you catch what you throw.
Doesn't C++ allow for strings?
It does, but to catch string, you need to throw string in first place.
is it possible to throw an exception that isn't a const char *,
You can throw literally anything. It is a good idea to throw special exception classes, like std::exception and derived from it.
Does throwing an exception in foo, terminate the foo function?
Yes, it does.
Are there cases where you could put the try and catch statements in the same function as the throw?
If you want, you can do that. There are not much cases where doing it is a good idea.
It looks like you need to get a good book and read chapter about exceptions. In the meantime this super-FAQ entry might help you/
You can throw an object of any type.
EDIT: (Hopefully I got this right now)
What you have done is throw a C-string, which is of type const char[13] in this case. C-Arrays will decay to pointers to their first element, in this case a pointer of type const char*.
Typically what you want to do is throw a predefined exception object. They can be found in header <stdexcept> and are derived from a base class std::exception. The derived exception classes are for instance std::logic_error, std::range_error, std::bad_alloc etc.
Their constructors take a string as argument, so you can for instance
throw std::logic_error{"Negative values not allowed."};
This message can be accessed in a catch statement like this:
catch(std::exception &e) // capture reference to base class
{
std::cout << e.what() << '\n'; // what() of derived is called, since virtual
}
If an exception is caught, so-called stack unwinding takes place. You can then deal with the error locally, or rethrow the exception. Only when an exception is thrown and never caught, std::terminate() is called an the program aborted.
You can put try/catch statements anywhere. However, remember what the term "exception" actually means. Cases that can easily dealt with using a simple conditional expression if (n < 0) break; or something like that, don't need the exception treatment. Especially if you can realistically expect this kind of unwanted condition to be true often. Then it is not something "exceptional".
If you decide to deal with an error using exceptions and they can not be treated locally, you may put try/catch clauses around the beginning and end of main().
Since you can put several catch statements directly after a try statement, you can then begin to deal with more specific errors, or simply catch anything via catch(...) { //... }.
This is all described in great detail (including pointers on when and when not to use it, in the C++ FAQ.
EDIT: Here's an example that makes use of try/catch statements. However, not an exception object is caught, but an int (errno). Just to show, that you can really throw/catch anything you like. Let process_several_files() be a function somewhere nested in your code:
std::vector<std::string> process_several_files(std::vector<std::string> const& files)
{
std::vector<std::string> contents{};
contents.reserve(files.size()); // files contains file names from user input
for (auto const& file : files)
{
try
{
contents.emplace_back(get_file_contents(file.c_str())); // A "C like" function. get_file_contents() will throw "errno", if a file does not exist
}
catch(int err)
{
std::cerr << "***Error while opening " << file << " : " << std::strerror(err) << "***\n";
continue; // "scope" didn't change, just keep iterating!
}
}
return contents;
}

Fix a return issue.Warning: control reaches end of non-void function in C++

I know this may look as a duplicate, but the other questions does not have the answer that I am looking for.
template <class T>
T Queue<T>::pop_back()
{
try
{
if (empty())
throw "The Queue is empty!";
size--;
back= (back- 1 + max_size) % (max_size);
return queue[back];
}
catch (char* strException)
{
cerr << "Error: " << strException << endl;
}
}
I have the above implementations of functions pop_back. Every time it removes the element it has to return that element. However, every time it tries to pop something from an empty Queue it says " terminate called after throwing an instance of 'char const*'
Aborted (core dumped)"
What are some tips and advice to fix this issue? I have a try catch block there but it is not helping much. The functions has to return something, or stop and return to main, from where it was called.
I am looking for a design patter so I can used it other times I encounter such a problem.
Basically what should I do when I need to return something but there is nothing I can return?
Thank you.
You should not catch the exception in the function itself - the exceptions should be used to communicate the problem to the callers - they're the ones who should know what's sensible handling in this situation.
The functions has to return something, or stop and return to main, from where it was called.
Not exactly - as above, it can throw and be continued from the catch() block most closely enclosing the place from which it was called.
Keep in mind that caller's who'd rather not do exception handling could easily test empty() or size() before deciding to attempt the pop... so it's quite reasonable to throw the exception back to them.
Further, don't throw a string literal... use a std::runtime_error("...") instead. Reasons here.
I am looking for a design patter so I can used it other times I encounter such a problem. Basically what should I do when I need to return something but there is nothing I can return?
As mentioned, throwing an exception is a normal way to deal with this, especially for something like pop from an empty stack. More generally though, other alternatives include:
return a sentinel value
for example, if the container stores ints, you might be able to return 0 or -1 or numeric_limits<int>::max, or for std::strings perhaps an empty one, but what would be best depends on the usage to which the client code puts the container
for a templated container it's hard to know whether a value of T can be used for this - for example if T is char and content from a binary file is being stored in the container, any character value you might want to use as a sentinel might also appear in the file; if you want to try this anyway, it's usually best to ask the caller to provide a sentinel value as a template parameter or constructor parameter.
return a std::optional<T> (still pending standardisation but might be offered by some compilers) or boost::optional<T>
return a std::pair<bool, T> where .second is only the popped value if .first is true, indicating success
return a [smart] pointer, but that's clumsy as you may have to dynamically allocate memory for a copy of the popped value; a smart pointer helps ensure the caller deletes the object later
just document that the caller must check empty() or size() first, and asserting that the container's not empty from within pop_back - this would halt the program if this "precondition" is not met by the caller
change the interface to bool pop_back(T& t) where the return value indicates success and that caller-specified T parameter will have been set.
None of these are worthy of being called "patterns" - patterns tend to refer to more complicated, high-level design aspects.
Replace the current code
template <class T>
T Queue<T>::pop_back()
{
try
{
if (empty())
throw "The Queue is empty!";
size--;
back= (back- 1 + max_size_) % (max_size);
return queue[back];
}
catch (char* strException)
{
cerr << "Error: " << strException << endl;
}
}
with something like this:
template< class Type >
auto Queue<Type>::pop_back()
-> Type
{
if( empty() ) { throw std::runtime_error( "The Queue is empty!" ); }
--size;
back = (back - 1 + max_size_) % (max_size_); // Note fix of name
return queue[back];
}
You want to throw the exception to the caller.
Using an exception within the function, to just jump to the code that outputs some text (and fails to return a function result), doesn't make sense.
In passing, it's a good idea to standardize on a single naming convention for members. The inadvertent mixing of max_size_ and max_size, which was most probably a bug, and anyway a serious imperfection, would not have happened with a single naming convention. And as it is, back as a data member is inconsistent with max_size_.
Also note the use of std::runtime_error instead of a string literal as the exception object. This supports catching of a std::exception. You might find some other standard exception class more suitable, more indicative of the particular problem, but I generally just use std::runtime_error.
Another reason why it's a good idea to use the standard exception classes is that it's otherwise easy to specify the wrong type in a catch.
For example, the catch in your code would not have worked:
#include <iostream>
using namespace std;
void foo()
{
try
{
throw "Blah blah!";
}
catch( char* s )
{
cout << "Caught exception internally in foo(): " << s << endl;
return;
}
}
auto main() -> int
{
try
{
foo();
}
catch( ... )
{
cout << "Failed to catch exception in foo()." << endl;
}
}
Output:
Failed to catch exception in foo().
Precissely the issue is that you have try-catch block.
If an exception is thrown, execution flow will go to the catch logic. It will print your statement, and the function will end without returning a value.
Re-throw the exception of add a return statement, either at the end of the catch block or at the end of the function (rethrowing seems the best option, since you do not handle the exception at all).

When is a function try block useful?

I'm wondering when programmers use function try blocks. When is it useful?
void f(int i)
try
{
if ( i < 0 )
throw "less than zero";
std::cout << "greater than zero" << std::endl;
}
catch(const char* e)
{
std::cout << e << std::endl;
}
int main() {
f(1);
f(-1);
return 0;
}
Output: (at ideone)
greater than zero
less than zero
EDIT: As some people might think that the syntax of function defintion is incorrect (because the syntax doesn't look familiar), I've to say that no its not incorrect. Its called function-try-block. See §8.4/1 [dcl.fct.def] in the C++ Standard.
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 (...) { ... } }
Function try block are useful for me in two contexts.
a) To have a catch all clause around main() allowing to write small utilities without having to worry about local error handling:
int main()
try {
// ...
return 0;
}
catch (...) {
// handle errors
return -1;
}
which is clearly just syntactic sugar for having a try/catch inside main() itself.
b) to handle exceptions thrown by base class constructors:
struct B {
B() { /*might throw*/ }
};
struct A : B {
A()
try : B() {
// ...
}
catch (...) {
// handle exceptions thrown from inside A() or by B()
}
};
Aside from the functional uses mentioned, you can use the function-try-block to save yourself one level of indentation. (Ack, an answer about coding styles!)
Typically you see examples with the function-try-block like so:
void f(/*...*/)
try {
/*...*/
}
catch(/*...*/) {
/*...*/
}
Where the function scope is indented to the same level as if there were no function-try-block. This can be useful when:
you have an 80 character column limit and would have to wrap lines given the extra indentation.
you are trying to retrofit some existing function with try catch and don't want to touch all the lines of the function. (Yeah, we could just use git blame -w.)
Though, for functions that are entirely wrapped with a function-try-block, I would suggest not alternating between some functions using function-try-blocks and some not within the same code base. Consistency is probably more important then line wrapping issues.
:)
Notes regarding how function try blocks operate:
For constructors, a function try block encompasses the construction of data members and base-classes.
For destructors, a function try block encompasses the destruction of data members and base-classes. It gets complicated, but for C++11, you have to include noexcept(false) in the declaration of your destructor (or that of a base/member class) or any destruction exception will result in termination at the conclusion of the catch block. It may be possible to prevent this by putting a return statement in the catch block (but this won't work for constructors).
A catch block in a constructor or destructor must throw some exception (or it will implicitly rethrow the caught exception). It is not legal to simply return (at least in constructor's function catch block). Note, however, that you could call exit() or similar, which might make sense in some situations.
A catch block can't return a value, so it doesn't work for functions returning non-void (unless they intentionally terminate the program with exit() or similar). At least that is what I've read.
The catch block for a constructor-function-try can't reference data/base members since they will have either have 1) not been constructed or 2) been destructed prior to the catch. As such, function try blocks are not useful for cleaning up an object's internal state -- the object should already be completely "dead" by the time you get there. This fact makes it very dangerous to use function try blocks in constructors, since it is difficult to police this rule over time if your compiler(s) don't happen to flag it.
valid (legal) uses
Translating an exception (to a different type/message) thrown during the constructor or it's base/member constructors.
Translating or absorbing and exception thrown during the destructor or it's base/member destructors (destructor etiquette notwithstanding).
Terminating a program (perhaps with a useful message).
Some kind of exception logging scheme.
Syntactic sugar for void-returning functions that happen to need a fully encapsulating try/catch block.
It might be useful if you want to catch exceptions from constructor's initializer.
However, if you do catch exception in constructor that way, you have to either rethrow it or throw new exception (i.e. you cannot just normally return from constructor). If you do not rethrow, it just happens implicitly.
#include <iostream>
class A
{
public:
A()
try {
throw 5;
}
catch (int) {
std::cout << "exception thrown\n";
//return; <- invalid
}
};
int main()
{
try {
A a;
}
catch (...) {
std::cout << "was rethrown";
}
}
Another thing you can use them for is to provide extra data during debugging, in a manner that doesn't interfere with the finished build. I haven't seen anyone else use or advocate it, but it's something I find convenient.
// Function signature helper.
#if defined(_WIN32) || defined(_WIN64)
#define FUNC_SIG __FUNCSIG__
#elif defined(__unix__)
#define FUNC_SIG __PRETTY_FUNCTION__
// Add other compiler equivalents here.
#endif /* Function signature helper. */
void foo(/* whatever */)
#ifdef DEBUG
try
#endif /* DEBUG */
{
// ...
}
#ifdef DEBUG
catch(SomeExceptionOrOther& e) {
std::cout << "Exception " << e.what() << std::endl
<< "* In function: " << FUNC_SIG << std::endl
<< "* With parameters: " << /* output parameters */ << std::endl
<< "* With internal variables: " << /* output vars */ << std::endl;
throw;
}
#endif /* DEBUG */
This would allow you to both obtain useful information while testing your code, and easily dummy it out without affecting anything.