Aquarius_Girl
Aquarius_Girl

Reputation: 22916

Where am I supposed to catch the C++ exception thrown in the constructor?

Header file:

#ifndef MUTEXCLASS
#define MUTEXCLASS

#include <pthread.h>

class MutexClass
{
private:
    pthread_mutex_t & _mutexVariable;
public:
    MutexClass (pthread_mutex_t &);
    ~MutexClass ();
};

#endif // MUTEXCLASS

Source file:

#include "mutexClass.h"
#include <stdexcept>

MutexClass::MutexClass (pthread_mutex_t & arg) : _mutexVariable (arg)
{
    _mutexVariable  = PTHREAD_MUTEX_INITIALIZER;
    int returnValue = pthread_mutex_lock (&_mutexVariable);
    if (returnValue > 0)
    {
        throw std::logic_error ("Mutex couldn't be locked!");
    }
}

MutexClass::~MutexClass()
{
    pthread_mutex_unlock (&_mutexVariable);
}

Where am I supposed to catch the exception thrown in the constructor?

Upvotes: 2

Views: 392

Answers (3)

g24l
g24l

Reputation: 3125

At the point of construction

try {
  MutexClass m(arg);
}catch( std::logic_error const & e)
{
}

or if you have a pointer

try {
  MutexClass * m = new MutexClass(arg);
}catch( std::logic_error const & e)
{
}

If you were able work with a pointer , passed to a function , surround the function.

E.g.

void funfun ( MutexClass * );

try {
  funfun(new MutexClass(arg));
}catch( std::logic_error const & e)
{
}

If you are going to construct the object in an initializer list:

class A
{
MutexClass mc;
A(pthread_mutex_t & m) try : mc(m)
{
} catch ( std::logic_error const & e )
{
// do something here to handle the failure 
// of mc(m) and the now the failure of A 
// must be handled in the construction point of A 
}
};

But now you have to handle the failure of the constructor of A as well.

Furthermore you should watch out for implicit conversions and copies, and you class is sadly copiable.

void funfun(MutexClass m );   

pthread_mutex & m;
try
{
  void funfun(m);
} catch( std::logic_error const & e )
{
}

Read before throwing from a constructor.

Also don't forget that such constructors are not good as static members. So this type of class may break your program

class maybreak 
{
private:

static MutexClass mc;

// ....

};

unless a wrapper function method is defined to put the construction of the static after your program actually starts (COFU).

Upvotes: -2

6502
6502

Reputation: 114481

An exception thrown in a constructor can be handled

  • by the code explicitly creating the object (try { MutexClass m; ... } catch(const std::logic_error& e) { ... })
  • by code creating an object that contains as member a MutexClass instance (including as base sub-object... i.e. by code that creates an object derived from MutexClass)
  • by code calling code doing the creation as exceptions will un-wind the stack until some code handles them

Note that for exceptions thrown in constructor of objects that are members of bigger objects (either for an has-a or a is-a relationship) there is a tricky part. The destructor of the bigger object will not be called if the costruction of a member throws an exception... only the already constructed members will be destroyed before propagating the exception. For example a class like:

struct Foo {
    MyData * data;
    MutexClass m;
    MyData() : data(new int[1000]) { }
    ~MyData() { delete[] data; } // NOT called if m constructor throws
};

will leak memory if MutexClass constructor throws an exception.

Also before writing an exception handler however ask yourself if catching the exception is the right thing to do (i.e. if you know what to do when that condition occurs). Catching an exception and "hiding" it because you don't know what to do in that case is the worst possible choice.

In the specific case if you cannot lock a freshly created mutex can you expect the system to be still in good enough shape that keeping it running is a good idea?

Upvotes: 5

Petr
Petr

Reputation: 9997

As with any exception, anywhere up the stack where you can handle the exception. This is no way different from handling exceptions thrown in functions.

Upvotes: 2

Related Questions