Lets consider having a class with a constructor throwing an exception like following:
class Class
{
public:
Class(type argument)
{
if (argument == NULL)
{
throw std::exception("Value cannot be null.\nParameter name: argument");
}
// Instructions
}
private:
// Properties
}
Since the class constructor might throw an exception we cannot declare an object directly.
Class obj(argument); // Harmful
Which means the constructor must be called must be using a try/catch
try
{
Class obj(argument);
}
catch (std::exception& ex)
{
std::cout << ex.what() << std::endl;
}
The problem is that we can only use the object inside the try block. The only way to use it outside of the try block is to declare a Class* pointer then use the new keyword to construct a new object then assign it's address to the previous pointer.
Class* pObj;
try
{
pObj = new Class(argument);
}
catch (std::exception& ex)
{
std::cout << ex.what() << std::endl;
}
So what is the standard way to define the previous class in order to create instances without using pointers or dynamic memory allocation?
Thank you in advance
Since the class constructor might throw an exception we cannot declare
an object directly.
Yes, you can. You only need to put it in a try block if you actually have a plan to deal with an exception right there, in the function. If you don't have such a plan, then just let the exception propogate (though you should catch it eventually, just to provide a report if nothing else).
But, assuming you do have a plan to handle the exception right there in the function, then the solution is simple.
try {
Class obj(argument);
// use obj here, inside the try block
}
catch(...) { ... }
// not here, outside the try block
Edit: By your comment below, either you are misunderstanding me, or I am misunderstanding you. Perhaps a concrete exaqmple is required. Let's say that this is your function which uses your class:
void Foobar(type argument)
{
Class obj(argument);
obj.method1(1,2,3);
obj.method2(3,4);
int x = Wizbang(obj);
gobble(x);
}
Now, you want to handle the exception that the Class constructor might throw. What I'm suggesting is putting all of that junk in the function, into a try block, thusly:
void Foobar(type argument)
{
try
{
Class obj(argument);
obj.method1(1,2,3);
obj.method2(3,4);
int x = Wizbang(obj);
gobble(x);
}
catch(std::exception& e)
{
std::cout << e.what() << std::endl;
}
}
If you can't do this, please explain why. You've said "I need access to use the object later", but you've provided no reason why "later" cannot mean "later within the same try block where the object was created". As such, your requirements are incomplete.
What you want is not (reasonably) possible. Suppose there were some method of doing what you want, that is, creating an object obj of type Class that was still in scope outside any relevant try{}catch{} construct used to handle exceptions in the constructor. Thw question to ask yourself is, if an exception were to be thrown during construction of the obj, and you somehow handled the exception and then execution were to continue in the block where the obj was still in scope, what exactly would the obj contain? It was never constructed, so just what would be in the obj????
Related
I have a factory method that returns object of a class type.
MyClass factory(string param1, ...) {
...
MyClass instance(param1);
...
if (smth) throw ...;
...
return instance;
}
The factory method may throw.
I'm trying to create an object of this class with exception handling. Something like this:
MyClass obj;
try {
obj = factory(...);
} catch (...) {
cout << "oops..." << endl;
}
The problem, of course, that this does not work as MyClass obj creates instance, but I would like to avoid creating instance because it is time and resource consuming.
Probably I can change the return type of factory to MyClass* but then I need to face new and delete.
Is there a way to do it without new and creating a temporary instance but with exception handling?
You can use std::optional (since C++17).
(emphasis mine)
The class template std::optional manages an optional contained
value, ...
If an optional<T> contains a value, the value is guaranteed to be
allocated as part of the optional object footprint, i.e. no dynamic
memory allocation ever takes place. Thus, an optional object models an
object, not a pointer, even though operator*() and operator->() are
defined.
e.g.
std::optional<MyClass> obj;
try {
obj = factory(...);
} catch (...) {
cout << "oops..." << endl;
}
BTW: If you just don't want to handle new and delete manually, smart pointers is a nice choice too.
How about:
try {
MyClass obj = factory(...);
DoJob(obj);
} catch (...) {
cout << "oops..." << endl;
}
This is a follow-up question of the post. Please see the end of this question for a definition of "function try block".
Question: If a function try block does not "handle" the exception raised in the constructor, why do we need them after all? Could you give an example taking advantage of function try block?
Considering the following code.
#include <iostream>
#include <new>
#include <exception>
using namespace std;
struct X {
int *p;
X() try : p(new int[10000000000]) {}
catch (bad_alloc &e) {
cerr << "exception caught in the constructor: " << e.what() << endl;
}
};
int main() {
try {
X x;
}
catch (exception &e){
cerr << "exception caught outside the constructor: " << e.what() << endl;
}
return 0;
}
The output is
exception caught in the constructor: std::bad_alloc
exception caught outside the constructor: std::bad_alloc
It seems to me that, no matter what I do in the function try block, the exception is always going to be thrown to the outer scope which calls the constructor, e.g. the X x; in the above code.
Definition of "function try block", excerpted from "C++ Primer 5th."
To handle an exception from a constructor initializer, we must write the constructor as a function try block. A function try block lets us associate a group of catch clauses with the initialization phase of a constructor (or the destruction phase of a destructor) as well as with the constructor’s (or destructor’s) function body.
You're right that the exception is always propagated.
The function try block enables you to catch that exception and e.g. destroy an object passed as argument (maybe this is a smart pointer class?), without introducing an artificial base class.
More generally, it gives you the ability to clean up state changes introduced by the call of the function.
For the case of a constructor:
With the exception propagation destructors are called for all successfully constructed sub-objects, including base class sub-objects (if any).
However, this not completely constructed object's own destructor is not called. The function try block is ideally not a device for doing things that would go in that destructor. The not-completely-created object's own destructor has nothing to do, for its task is to clean up state changes introduced by the constructor body and/or later member function calls, and with a common "rule of zero" design there's no such as yet.
When a constructor throws, the corresponding destructor doesn't run. That's the reason for the quote in your book : cleanup has to be done by the constructor itself.
But your example shows that the exception propagates. This is necessary since the constructor failed, and therefore no object was created. The calling code should not proceed as if the constructor created an object.
I have a class that can throw an exception in its constructor. How can I declare an instance of that class in a try/catch block, while still making it available in the right scope?
try { MyClass lMyObject; }
catch (const std::exception& e) { /* Handle constructor exception */ }
lMyObject.DoSomething(); // lMyObject not in scope!
Is there an alternative way to accomplish this, while respecting the RAII idiom?
I'd prefer not to use an init() method for two-phased construction. The only other thing I could come up with was:
MyClass* lMyObject;
try { lMyObject = new MyClass(); }
catch (const std::exception& e) { /* Handle constructor exception */ }
std::shared_ptr<MyClass> lMyObjectPtr(lMyObject);
lMyObjectPtr->DoSomething();
Works OK, but I'm not happy with the raw pointer in scope and pointer indirection. Is this just another C++ wart?
If a constructor throws that means the object failed to initialize and hence it failed to start its existence.
MyClass* lMyObject;
try { lMyObject = new MyClass(); }
catch (std::exception e) { /* Handle constructor exception */ }
In the above if the constructor throws an exception, lMyObject is left uninitialized, in other words, the pointer contains an indeterminate value.
See classic Constructor Failures for a detailed explanation:
We might summarize the C++ constructor model as follows:
Either:
(a) The constructor returns normally by reaching its end or a return statement, and the object exists.
Or:
(b) The constructor exits by emitting an exception, and the object not only does not now exist, but never existed.
There are no other possibilities.
The best way of writing your code is this:-
MyClass lMyObject;
lMyObject.DoSomething();
No trys, catches, or pointers.
If the constructor throws, then DoSomething can't get called. Which is right: If the constructor threw, then object was never constructed.
And, importantly, don't catch (or even catch/rethrow) exceptions unless you have something constructive to do with them. Let exceptions do their job and ripple up until something that knows how to handle them can do its job.
Constructors are for putting an object into a consistent state and establishing class invariants. Allowing an exception to escape a constructor means that something in that constructor has failed to complete, so now the object is in some unknown weird state (which may include resource leaks now too). Since the object's constructor has not completed, the compiler will not cause it's destructor to be invoked either. Perhaps what you're looking for is to catch the exception inside the constructor. Assuming it's not rethrown, this would cause the constructor to complete execution, and the object is now fully-formed.
You don't need to use shared_ptr, use unique_ptr:
std::unique_ptr<MyClass> pMyObject;
try { pMyObject.reset(new MyClass()); }
catch (std::exception &e) { /* Handle constructor exception */ throw; }
MyClass &lMyObject = *pMyObject;
lMyObject.DoSomething();
Obviously, it's your responsibility to ensure that the program does not fall through the catch block without either initialising pMyObject, or exiting the function (e.g. via return or throw).
If available, you can use Boost.Optional to avoid using heap memory:
boost::optional<MyClass> oMyObject;
try { oMyObject.reset(MyClass()); }
catch (std::exception &e) { /* Handle constructor exception */ throw; }
MyClass &lMyObject = *oMyObject;
lMyObject.DoSomething();
You could set up MyClass's copy constructor to accept garbage input, thereby effectively declaring a pointer with your declaration of the object. Then you could manually call the default constructor within the try block:
MyClass lMyObject(null); // calls copy constructor
try {
new (lMyObject) MyClass(); // calls normal constructor
}
catch (const std::exception& e) { /* Handle constructor exception */ }
lMyObject.DoSomething();
Please have a look at demo code :
class myError
{
const char* str;
public:
myError():str(NULL) {}
myError(const char* temp)
{
str = temp;
}
const char* what()
{
return str;
}
};
class ab
{
int x;
public:
ab() try :x(0)
{
throw myError("error occured in the constructor of class ab");
}
catch(myError& temp)
{
std::cout<<"Handler no. 1 of ab constructor"<<std::endl;
}
};
int main () try
{
ab bb;
cout << "Resumed execution!" << endl;
return 0;
}
catch(myError& temp)
{
std::cout<<"Handler below the main function"<<std::endl;
std::cout<<"And the error is :" <<temp.what();
}
My Questions :
Why only function try block's handler of ctor and dtor only rethows the exception? ,
and when you simply throw exception inside ctor , its handler doesn't rethrows the object? i.e
Ctor::Ctor()
{
try{
throw Excep1();
}
catch(Excep1& temp) {
std::cout<<"Doesn't rethrows the exception object";
}
}
I wanna know that how to resume the control back to cout << "Resumed execution!" << endl; , after handling rethrown object?
why is it often said that we shouldn't place function try block on dtor of base class?
The usual rule is that a catch block doesn't rethrow unless you ask it
to. How would you stop the exception from propagating otherwise. In
the case of a constructor, however, if something in the initialization
list throws, then you haven't got a fully constructed object; there is
nothing you could do with the object, not even call the destructor on
it. And if the function catch block of the constructor doesn't
rethrow, what is it going to do, since it cannot simply return (and
leave the variable on the stack)?
In all other cases, it's up do the function containing the catch block
to know what to do. In the case of your main, for example, you could
write:
try {
ab bb;
} catch (...) {
}
std::cout << "Resumed execution!" << std::endl;
What you can't do is execute code where bb would be in scope and
accessible, but not have been correctly constructed.
As for why you shouldn't place a function try block on the destructor of a
base class, I've never heard that rule. In general, destructors
shouldn't throw, so there's no point in wrapping them in a try block,
period.
For the second question, destructors shouldn't be throwing period. Consider a case where your destructor is freeing a lot of memory through delete. What would happen if your destructor threw an error before finishing the clean up? You now have a memory leak. If your destructor is causing a runtime error, then you probably have problems elsewhere in your code that you need to fix.
As usually, Herb Sutter knows and explains everything:
If the handler body contained the statement "throw;" then the catch block would obviously rethrow whatever exception A::A() or B::B() had emitted. What's less obvious, but clearly stated in the standard, is that 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.
More in his article
Is it possible to handle exceptions in these scenarios:
thrown from constructor before entering main()
thrown from destructor after leaving main()
You can wrap up your constructor withing a try-catch inside of it.
No, you should never allow exception throwing in a destructor.
The funny less-known feature of how to embed try-catch in a constructor:
object::object( int param )
try
: optional( initialization )
{
// ...
}
catch(...)
{
// ...
}
Yes, this is valid C++. The added benefit here is the fact that the try will catch exceptions thrown by the constructors of the data members of the class, even if they're not mentioned in the ctor initializer or there is no ctor initializer:
struct Throws {
int answer;
Throws() : answer(((throw std::runtime_error("whoosh!")), 42)) {}
};
struct Contains {
Throws baseball;
Contains() try {} catch (std::exception& e) { std::cerr << e.what() << '\n'; }
};
Yes: don't use dangerous global objects!
It might be possible to set an exception handler before construction / destruction of the objects in question, that one should be able to handle those exceptions.
For constructors, there's some weird new syntax that allows exceptions to be caught within the constructor. Not sure how that works, and it's not commonly implemented in many compilers.
For destructors, you have to wrap the content of the destructor in a try { code(); } catch(...) {} block. Which may not always be the desired behavior, depending on what you want to achieve in that destructor.
Short answer: no.
Any global object that throws an exception in its constructor will cause an unhandled exception (that is, terminate be called).
Any class that throws an exception in its destructor is a broken class.
Using the singleton pattern rather than globals will give you more options.