Best way to deal "locally" with exceptions thrown in object constructor - c++

I have been thinking for some time now about this question, but I have not found an answer online satisfactory enough, yet. So here I am.
Assumptions
For the sake of clarity let us restrict ourselves to C++11 and a custom object. By custom object, I mean a user-defined class that the developer has full control of. All the code snippets below are not meant to be compilable or even syntactically correct. They just illustrate a concept.
Boundary conditions
Our object has a nontrivial constructor that can throw exceptions if an error is encountered. When constructing this object I would like to catch and deal with the exceptions as close as possible to the object creation point, to make the code more readable and catching only the constructor exceptions and nothing else.
Example 1
This example is not ideal because this is exactly what I am trying to avoid: dealing with constructor exceptions far away from the constructor.
class MyClass {
public:
MyClass() {
throw 1;
}
}
int main() {
try {
MyClass my_obj;
try {
// Do something with my_obj that may throw
} catch (...) {
// deal with exceptions
}
} catch(...) {
// deal with constructor exceptions
}
}
Example 2
Here I use a std::unique_ptr to separate the object declaration and initialization. The downside is that I now create the object on the heap instead of the stack even if I have no strong reason to do that.
class MyClass {
public:
MyClass() {
throw 1;
}
}
int main() {
std::unique_ptr<MyClass> my_obj_ptr;
try {
my_obj_ptr = boost::make_unique<MyClass>();
} catch (...) {
// deal with constructor exceptions
}
// continue to use my_obj
}
Example 3
Modify the object internal state and check that.
class MyClass {
private:
good_internal_state;
public:
MyClass() : good_internal_state(true) {
try {
throw 1;
} catch(...) {
good_internal_state = false;
}
}
bool IsInternalStateGood() {
return good_internal_state;
}
}
int main() {
MyClass my_obj;
if (!my_obj.IsInternalStateGood()) {
// Do something
}
// continue to use my_obj
}
Right now I am leaning towards the Example 2 case but I would like to know what is the most syntactically correct way to accomplish what I want.

I wouldn't say any of those versions is more or less correct (except for some typos). Example 2 looked like the one I would use. Here scoping seems to be the largest problem. The variable needs to declared outside of the try but must be initialized inside. If you don't like to use the heap std::optional could be usefull:
int main() {
std::optional<MyClass> maybeMyClass;
try {
maybeMyClass.emplace(/*constructor parameters*/);
} catch (...) {
// deal with constructor exceptions
}
// continue to use my_obj
maybeMyClass->foo();
}
Allthough the syntax could imply otherwise, the value managed by std::optional is allocated as the footprint of this std::optional (on the stack in this case).
You could also use a factory function createMyClass that would return a std::optional, this would require MyClass to have a move constructor, which shouldn't be to expensive.

Related

Conditionally dealing with exceptions during initialization of member variables

Hello good folk of StackOverflow.
Is there a better way of dealing with exceptions in the constructor of member variables? I am having to interact with a library class that may or may not throw an exception in it's constructor (cannot be checked ahead of time) and I want to avoid the use of pointers in my class (if there is a crash, I want all destructors to be properly called even if I mess up). I have currently settled on this implementation (included a dummy stub for an example):
class class_I_have_no_control_over{
public:
class_I_have_no_control_over( int someArgument )
{
if( someInternalConditionThatCantBeTestedExternally )
throw anException;
}
class_I_have_no_control_over( )
{ //Does not throw
}
}
class MyClass{
private:
class_I_have_no_control_over memberVariable;
public:
MyClass()
{
try{
class_I_have_no_control_over tempVariable( 24 );
memberVariable = std::move( tempVariable );
}catch(...)
{
class_I_have_no_control_over tempVariable( );
memberVariable = std::move( tempVariable );
}
}
}
The first method I considered is try catch initializer list : i.e.
class MyClass{
private:
OtherClassThatTrowsOnConstruct member;
MyClass()
try:
member()
{//Normal constructor
}
catch(...)
{//Can translate an exception but cant stop it.
}
But that method can only be used to translate exceptions, not stop them (if you don't throw an exception, the run-time will re-throw the original exception).
Some would say to use dynamic allocation (i.e. pointers with new and delete keywords) but as this library handles shared memory between processes, I am a little weary of what would happen to the dynamic memory contents in the event of a crash in one of the applications (ex. destructor never called and another application is waiting for the one that is no longer running never realizing that it is no longer listening).
The first version can be simplified somewhat, without changing its behaviour:
MyClass() try {
memberVariable = class_I_have_no_control_over(24); // move from temporary
} catch (...) {
// no need to do anything; memberVariable is already default-constructed
// Unless the class is so evil that move-assignment might fail and leave
// the target in a messed-up state. In which case you probably want
memberVariable = class_I_have_no_control_over();
// If that fails, you should probably give up and let the exception go.
}
Unless you have further constraints (such as the class not being movable), this is the best way to deal with your situation. If it were unmovable, then dynamic allocation is probably a reasonable option; use a smart pointer, probably std::unique_ptr, to make sure it's destroyed along with the MyClass object.
#include <memory>
class MyClass{
private:
std::unique_ptr<unmovable_evil> memberVariable;
public:
MyClass() try {
memberVariable.reset(new unmovable_evil(24));
} catch(...) {
memberVariable.reset(new unmovable_evil);
}
};
You might also consider boost::optional as a not-quite-standard alternative to dynamic allocation.

Avoiding heap allocation with "throwing" constructors

Say I have some class Foo which does not define a default constructor and throws in a non-default constructor. When initializing a new object of the type, I'd like to catch any exceptions and return, otherwise continue using the object. I'm noticing it difficult, if at all possible, to initialize this object on the stack or through use of a shared pointer, because I'm trying to avoid managing memory.
Fail 1
Foo f; // doesn't work, no default constructor
try { f = Foo(...); }
Fail 2
try {
Foo f(...)
}
catch(...) {}
// doesn't work, f is inaccessible
Fail 3
boost::shared_ptr<Foo> pf;
try { pf = new Foo(...); } // no assignment operator
Must I...
Foo *f;
try { f = new Foo(...) } // okay, let's just manage the memory
Is there a way?
Edit
Okay, so this works, albeit not the cleanest. Is there a more "standard" way?
boost::shared_ptr<Foo> pf;
try { pf = boost::shared_ptr<Foo>(new Foo(...)); }
Smart pointers have a reset method:
boost::shared_ptr<Foo> f;
//...
f.reset(new Foo(...));
This solves your "Fail #3" and allows you to do what you want.
The correct approach to keep f stack-based is to respect the scope:
try {
Foo f(...);
... entire code using f ...
}
catch(...) {}
One solution could be to use boost::optional (or C++14's std::optional):
boost::optional<Foo> f;
try { f = Foo(...); }
Your smart pointer case and likes work fine if you use the proper .reset() method.
However the question does not fit normal use cases, either the class is misdesigned or you use it incorrectly. Normal use should just go ahead like case#1 with F inside the block. Or without try block and leaving catch to upstream.
EDIT:
Addressing recent comments as well as original issue, I keep my position that try blocks in end-user code are not welcome. For situations where I deal third-party components with certain throw strategy, if it does not fit my needs I write wrappers, converting exception to error-return or error code throwing exception. And use that extended component.
For this case the user is bothered by throwing ctor. So it would be handled by wrapping the ctor in a function:
Foo* new_foo( ARGS )
{
try{
return new Foo( ARGS );
}
catch( const FooException& )
{
return NULL;
}
}
Then have the client code free of try blocks, and more importantly, free of assignments. Just const unique_ptr<Foo> p(new_foo(...)) will do.

Avoiding copies in exception handling

Can I avoid the copying of object in the following way?
MyClass Obj;
try {
throw &Obj;
}
catch(MyClass *a) {
}
If the object is too expensive to copy, it should not be thrown as an exception - full stop. Exception classes should be fairly simple and light-weight. And you should always catch exceptions by reference (probably by const reference) - catching pointers is bad style. So your code should better be written:
try {
throw MyClass();
}
catch( const MyClass & a) {
}
In response to your comment, this:
struct A {
A() {}
private:
A( const A & ) {}
};
int main() {
throw A();
}
should be an error. But you simply should not be prohibiting copying of classes you want to throw as exceptions - why are you doing this?
Don't do it.
Consider this program:
#include <iostream>
#define X() (std::cout << __FUNCTION__ << "\n")
struct MyClass {
MyClass() { X(); }
~MyClass() { X(); }
};
void f() {
MyClass Obj;
throw &Obj;
}
int main() {
try {
f();
} catch(MyClass *a) {
X();
}
}
the output of which is this:
MyClass
~MyClass
main
Notice that the pointed-to object is destroyed before the program entered the catch block. This means that we must not dereference a in the catch block, severely limiting its usefulness.
It is syntactically correct and avoids the copy since the reference is being passed. But, usually an standard nameless exception object is constructed and is caught by the catch statement.
The only way to avoid copying an exception object is to throw a pointer to the object, as you have done in your example. You must make sure that the object is static or heap allocated, not a local object that will disappear after leaving the code block during the throw.
Edit: Another approach comes to mind. You can create your own exception class (which should be derived from std::exception or one of its children) with the pointer as a member, then throw that. If you use a smart pointer such as shared_ptr you won't have to worry about the lifetime of the contained object.

Is there a potential for resource leak/double free here?

The following sample (not compiled so I won't vouch for syntax) pulls two resources from resource pools (not allocated with new), then "binds" them together with MyClass for the duration of a certain transaction.
The transaction, implemented here by myFunc, attempts to protect against leakage of these resources by tracking their "ownership". The local resource pointers are cleared when its obvious that instantiation of MyClass was successful. The local catch, as well as the destructor ~MyClass return the resources to their pool (double-frees are protected by teh above mentioned clearing of the local pointers).
Instantiation of MyClass can fail and result in an exception at two steps (1) actual memory allocation, or (2) at the constructor body itself. I do not have a problem with #1, but in the case of #2, if the exception is thrown AFTER m_resA & m_resB were set. Causing both the ~MyClass and the cleanup code of myFunc to assume responsibility for returning these resources to their pools.
Is this a reasonable concern?
Options I have considered, but didn't like:
Smart pointers (like boost's shared_ptr). I didn't see how to apply to a resource pool (aside for wrapping in yet another instance).
Allowing double-free to occur at this level but protecting at the resource pools.
Trying to use the exception type - trying to deduce that if bad_alloc was caught that MyClass did not take ownership. This will require a try-catch in the constructor to make sure that any allocation failures in ABC() ...more code here... wont be confused with failures to allocate MyClass.
Is there a clean, simple solution that I have overlooked?
class SomeExtResourceA;
class SomeExtResourceB;
class MyClass {
private:
// These resources come out of a resource pool not allocated with "new" for each use by MyClass
SomeResourceA* m_resA;
SomeResourceB* m_resB;
public:
MyClass(SomeResourceA* resA, SomeResourceB* resB):
m_resA(resA), m_resB(resB)
{
ABC(); // ... more code here, could throw exceptions
}
~MyClass(){
if(m_resA){
m_resA->Release();
}
if(m_resB){
m_resB->Release();
}
}
};
void myFunc(void)
{
SomeResourceA* resA = NULL;
SomeResourceB* resB = NULL;
MyClass* pMyInst = NULL;
try {
resA = g_pPoolA->Allocate();
resB = g_pPoolB->Allocate();
pMyInst = new MyClass(resA,resB);
resA=NULL; // ''ownership succesfully transfered to pMyInst
resB=NULL; // ''ownership succesfully transfered to pMyInst
// Do some work with pMyInst;
...;
delete pMyInst;
} catch (...) {
// cleanup
// need to check if resA, or resB were allocated prior
// to construction of pMyInst.
if(resA) resA->Release();
if(resB) resB->Release();
delete pMyInst;
throw; // rethrow caught exception
}
}
Here is your chance for a double call to release:
void func()
{
MyClass a(resourceA, resourceB);
MyClass b(a);
}
Whoops.
If you use an RIAA wrapper fro your resources you will be much less likely to make mistakes. Doing it this way is error prone. You are currently missing the copy constructor and assignment operator on MyClass that could potentially lead to a double call to Release() as shown above.
Because of the complexity of handling resource a class should only own one resource. If you have multiple resource delegate their ownership to a class that it dedicated to their ownership and use multiple of these objects in your class.
Edit 1
Lut us make some assumptions:
Resources are shared and counted. You increment the count with Acquire() and decrement the count with Release(). When count reaches zero they are automatically destroyed.
class ReferenceRapper
{
ReferenceBase* ref;
public:
ReferenceWrapper(ReferenceBase* r) : ref (r) {/* Pool set the initial count to 1 */ }
~ReferenceWrapper() { if (ref) { ref->Release();} }
/*
* Copy constructor provides strong exception guarantee (aka transactional guarantee)
* Either the copy works or both objects remain unchanged.
*
* As the assignment operator is implemented using copy/swap it also provides
* the strong exception guarantee.
*/
ReferenceWrapper(ReferenceWrapper& copy)
{
if (copy.ref) {copy.ref->Acquire();}
try
{
if (ref) {ref->Release();}
}
catch(...)
{
if (copy.ref)
{ copy.ref->Release(); // old->Release() threw an exception.
// Must reset copy back to its original state.
}
throw;
}
ref = copy.ref;
}
/*
* Note using the copy and swap idium.
* Note: To enable NRVO optimization we pass by value to make a copy of the RHS.
* rather than doing a manual copy inside the method.
*/
ReferenceWrapper& operator(ReferenceWrapper rhsCopy)
{
this->swap(rhsCopy);
}
void swap(ReferenceWrapper& rhs) throws ()
{
std::swap(ref, rhs.ref);
}
// Add appropriate access methods like operator->()
};
Now that the hard work has been done (managing resources). The real code becomes trivial to write.
class MyClass
{
ReferenceWrapper<SomeResourceA> m_resA;
ReferenceWrapper<SomeResourceB> m_resB;
public:
MyClass(ReferenceWrapper<SomeResourceA>& a, ReferenceWrapper<SomeResourceB>& b)
: m_resA(a)
, m_resB(b)
{
ABC();
}
};
void myFunc(void)
{
ReferenceWrapper<SomeResourceA> resA(g_pPoolA->Allocate());
ReferenceWrapper<SomeResourceB> resB(g_pPoolB->Allocate());
std::auto_ptr<MyClass> pMyInst = new MyClass(resA, resB);
// Do some work with pMyInst;
}
Edit 2 Based on comment below that resources only have one owner:
If we assume a resource has only one owner and is not shared then it becomes trivial:
Drop the Release() method and do all the work in the destructor.
Change the Pool methods so that the construct the pointer into a std::auto_ptr and return the std::auto_ptr.
Code:
class MyClass
{
std::auto_ptr<SomeResourceA> m_resA;
std::auto_ptr<SomeResourceB> m_resB;
public:
MyClass(std::auto_ptr<SomeResourceA>& a, std::auto_ptr<SomeResourceB>& b)
: m_resA(a)
, m_resB(b)
{
ABC();
}
};
void myFunc(void)
{
std::auto_ptr<SomeResourceA> resA(g_pPoolA->Allocate());
std::auto_ptr<SomeResourceB> resB(g_pPoolB->Allocate());
std::auto_ptr<MyClass> pMyInst = new MyClass(resA, resB);
// Do some work with pMyInst;
}
I don't see any leak in this small code.
If the constructor throws exception, then the destructor would not be called, since the object never existed. Hence I don't see double-delete either!
From this article by Herb Sutter :Constructor Exceptions in C++, C#, and Java:
constructor conceptually turns a
suitably sized chunk of raw memory
into an object that obeys its
invariants. An object’s lifetime
doesn’t begin until its constructor
completes successfully. If a
constructor ends by throwing an
exception, that means it never
finished creating the object and
setting up its invariants — and at
the point the exceptional constructor
exits, the object not only doesn’t
exist, but never existed.
A destructor/disposer conceptually
turns an object back into raw memory.
Therefore, just like all other
nonprivate methods,
destructors/disposers assume as a
precondition that “this” object is
actually a valid object and that its
invariants hold. Hence,
destructors/disposers only run on
successfully constructed objects.
I think this should clear your doubts!
Your code is fine. But to make it even better, use some kind of smart-pointer!
Edit: for example you can use shared_ptr:
class SomeExtResourceA;
class SomeExtResourceB;
class MyClass {
private:
// These resources come out of a resource pool not allocated with "new" for each use by MyClass
shared_ptr<SomeResourceA> m_resA;
shared_ptr<SomeResourceB> m_resB;
public:
MyClass(const shared_ptr<SomeResourceA> &resA, const shared_ptr<SomeResourceB> &resB):
m_resA(resA), m_resB(resB)
{
ABC(); // ... more code here, could throw exceptions
}
}
};
void myFunc(void)
{
shared_ptr<SomeResourceA> resA(g_pPoolA->Allocate(), bind(&SomeResourceA::Release, _1));
shared_ptr<SomeResourceB> resB(g_pPoolB->Allocate(), bind(&SomeResourceB::Release, _1));
MyClass pMyInst(resA,resB);
// you can reset them here if you want, but it's not necessery:
resA.reset(), resB.reset();
// use pMyInst
}
I find this solution with RAII much simpler.
Just put if (pMyInst) { ... } around release/delete code in your catch and you are fine.
The classic usage to explicitly take ownership is the std::auto_ptr
Something like this:
std::auto_ptr<SomeResourceA>(g_pPoolA->Allocate()) resA;
std::auto_ptr<SomeResourceB>(g_pPoolB->Allocate()) resB;
pMyInst = new MyClass(resA.release(),resB.release());
You transfer the ownership when you call the constructor.

exception handling in constructor’s initializer list

In my project I found a piece of code in which a method was getting called in constructor's initializer list.
Test2(Test* pTest):m_pTest(pTest), m_nDuplicateID(pTest->getTestID())
{
}
I observed that there is a chance that the users of Test2 might pass NULL to the constructor. Since the pointer is used without validation there are chances of Access Violation.
This triggered me to look into exception handling in constructor's initializers list. I found in one of the article that try can be used inside initializer list. I wrote small test program to test this concept:
//Test class stores the unique ID and returns the same with API getTestID
class Test
{
public:
Test(int nID):m_nID(nID){
}
int getTestID() const
{
return m_nID;
}
private:
int m_nID;
};
class Test2
{
public:
Test2(Test* pTest)
try :m_pTest(pTest), m_nDuplicateID(pTest->getTestID())
{
}
catch (...)
{
cout<<"exception cought "<< endl;
}
void printDupID()
{
cout<<"Duplicate ID" << m_nDuplicateID << endl;
}
private:
Test* m_pTest;
int m_nDuplicateID;
};
int main(int argc, char* argv[])
{
Test* pTest = new Test(10);
Test2 aTest2(pTest);
aTest2.printDupID();
delete pTest;
return 0;
}
This code is not getting compiled in VC6.0. Do I need to make any changes to make it compile in VC 6.0?
Also, in one of the article I found that using try in constructor's initializer list does not strictly confirms to C++ standards. In that case, how do we handle the exceptions in constructor's initializers list (standard way of handling )?
Thanks.
C++ Standard Section 15 / 3
A function-try-block associates a
handler-seqwith thector-initializer,
if present, and the function-body. An
exception thrown during the execution
of the initializer expressions in the
ctor-initializer or during the
execution of the function-body
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.
class C
{
int i;
double d;
public:
C(int, double);
};
C::C(int ii, double id)
try : i(f(ii)), d(id)
{
//constructor function body
} catch (...)
{
//handles exceptions thrown from the ctor-initializer
//and from the constructor functionbody
}
Firstly, if you dereference the NULL pointer standard C++ does not guarantee that that an exception will be thrown, so your code is useless for this case.
Secondly, if an exception were thrown, what would your exception handler do?
Thirdly, constructor/function exception blocks are widely considered to be awaste of time - take a look at this http://www.gotw.ca/gotw/066.htm and other articles on Herb Sutter's GotW site.
According to this article, it looks like you just can't do that in VC++ 6.0
You'd either have to upgade to 7.0 or just do the initialization in the constructor body instead.
Can't you just use a function to check the ptr, e.g.:
template<typename P>
P* checkPtr (P* p)
{
if (p == 0)
throw std::runtime_error ("Null pointer");
return p;
}
class Test2
{
public:
Test2 (Test* pTest)
: m_pTest (checkPtr (pTest))
{
}
Test* m_pTest;
};
People still use VC6?
Seriously, VC6 is hardly a standards-complaint compiler. Do yourself a favor and at least get VS2005. VC6 is your problem.
Try VS2008 express and see if it compiles.
The other option, of course, is to take a reference on construction, which needs to be bound.
(for fellow googlers)
Another solution if we don't want to store a copy of the ptr / shared_ptr :
class Foo::Pimpl
{
public:
bool paramTest_;
Pimpl(ConstNodePtr root)
try :
paramTest_( root ? true : throw std::invalid_argument("Foo (pimpl) constructed from NULL node")),
...
{
...
} catch (...)
{
throw; // rethrow
}
There are many useful answers already, but I'll try to add a little bit, maybe it will help someone.
First of all, as others already mentioned - dereferencing a nullptr or invalid pointer (address) doesn't throw an exception in the standard C++. MSVC supports it through its Structured Exception Handling, but it's not portable. Read more about it in this answer.
The function try block in a constructor doesn't allow you to suppress the exception, it will propagate anyway if you don't throw another one. And when you enter the catch clause, all members of the class are already destroyed. So the only plausible thing you can do in it is to log the error somehow or maybe change some global variables. That's why it's considered more or less useless.
As for your initial code
Test2(Test* pTest):m_pTest(pTest), m_nDuplicateID(pTest->getTestID())
{
}
you could use the ternary operator to check for pTest's nullness just in the initializer list and do some appropriate actions in case it is null - just set m_nDuplicateID to nullptr or some other value depending on its type, call another function and use it return type, etc:
Test2(Test* pTest):
m_pTest(pTest),
m_nDuplicateID( pTest ? pTest->getTestID() : /*some value or call*/ )
{
}
you could even use several nested ternary operators to create more complicated execution flows.
And just for completeness, it's not the case with your code, but it may worn someone in the same situation. If you used your class's member m_pTest to initialize m_nDuplicateID, that would depend on the order of these members in class's declaration, because class members in the initializer list get initialized in the order of declaration and not in the order they appear in the initializer list itself, so it can be a problem and it's better to avoid members initialization order dependencies:
class A
{
A( B* pTest );
int m_nDuplicateID;
B* m_pTest;
};
A::A( B* pTest ) :
m_pTest( pTest ),
m_nDuplicateID( m_pTest->someMethod() ) // here m_pTest isn't initialized yet,
// so access violation probably
{
}