exceptions in constructor

V

vaclavpich

Hi
I've a question about constructors and exceptions.
//************************************************************
class CObject
{
public:
// ctor
CObject();
// dtor
~ CObject();

// ... methods
};

CObject::CObject()
{
// 1) if ( FAILED( LoadLibrary(...) )) throw exception1;

// 2) if ( FAILED(CoInitialize( 0 )) throw exception2;

// 3) if ( FAILED( CoCreateInstance(....))) throw exception3;
}

CObject::~CObject()
{
// 1) release COM interface

// 2) CoUninitialize();

// 2) FreeLibrary
}

int main(int avgv, char** argc)
{
try{
CObject* ptrObj = new CObject;
}
catch(exception& exc)
{...}
return 0;
}
//****************************************************************
When an error occurs in constructor there is only one way how to say
that samething wrong happen.You can throw an exception but is then a
pointer to CObject valid ?
So can you call detructor ~CObject() to release resources. I mean
this : delete ptrObj;

Is really constructor good place to attach resources (load library or
to get COM interface) ?
I'm not sure.

I've seen another way. Constructor and destructor are very simple
methods.
All resources are attached in method Initialize and released in
Uninitialize.
These methods can return error codes.

Can anybody explain it to me.
Thanks.
 
E

Erik Wikström

Hi
I've a question about constructors and exceptions.
//************************************************************
class CObject
{
public:
// ctor
CObject();
// dtor
~ CObject();

// ... methods
};

CObject::CObject()
{
// 1) if ( FAILED( LoadLibrary(...) )) throw exception1;

// 2) if ( FAILED(CoInitialize( 0 )) throw exception2;

// 3) if ( FAILED( CoCreateInstance(....))) throw exception3;
}

CObject::~CObject()
{
// 1) release COM interface

// 2) CoUninitialize();

// 2) FreeLibrary
}

int main(int avgv, char** argc)
{
try{
CObject* ptrObj = new CObject;
}
catch(exception& exc)
{...}
return 0;
}
//****************************************************************
When an error occurs in constructor there is only one way how to say
that samething wrong happen.You can throw an exception but is then a
pointer to CObject valid ?
So can you call detructor ~CObject() to release resources. I mean
this : delete ptrObj;

No, there will be no object, so you can not get a pointer to it. On the
other hand you do not have to worry about destroying it either, it is
all taken care of by new.
Is really constructor good place to attach resources (load library or
to get COM interface) ?
I'm not sure.

The C++ programming RAII idiom relies on the constructor allocating all
the resources needed. You should, however, take care to ensure that you
do not leek resources if the constructor throws by doing some exception
handling inside the constructor too:

CObject::CObject()
{
// LoadLibrary(...), if this throws no harm done

try {
// Allocate(...), if this throws we need to clean up
}
catch(...) {
// Clean up, free allocated memory etc.
throw; // Re-throw the exception
}

try {
// Initialise(...), will require clean up too
}
catch(...) {
// Clean up from initialisation
// Free memory etc
throw; // Re-throw the exception
}
}
I've seen another way. Constructor and destructor are very simple
methods.
All resources are attached in method Initialize and released in
Uninitialize.
These methods can return error codes.

This is called two stage initialisation, and many consider it a bad thing.
 
P

Peter

CObject::CObject()
{
// 1) if ( FAILED( LoadLibrary(...) )) throw exception1;

// 2) if ( FAILED(CoInitialize( 0 )) throw exception2;

// 3) if ( FAILED( CoCreateInstance(....))) throw exception3;
}

CObject::~CObject()
{
// 1) release COM interface

// 2) CoUninitialize();

// 2) FreeLibrary
}



you should put the separate objects (HANDLE returned by LoadLibrary, CoInitialize()/CoUninitialize() and CoCreateInstance()) into separate classes and combine these classes into base-class or member-class relationships.
Doing it this way you don't have to clean up yourself anymore but rely on the code generation features of the compiler. And you can reuse these classes next time you're calling these functions.
And the caller of you'r code will get rich error information.

class CPLoadLibrary
{ private:
HINSTANCE h;
public:
inline CPLoadLibrary(const _TCHAR *pName)
{ if (!(h = LoadLibrary(pName)))
throwSystemException(
GetLastError(),
CString(_T("LoadLibrary(\"")) + CString(pName) + CString(_T("\")")));
}
inline ~CPLoadLibrary(void)
{ FreeLibrary(h);
}
inline void *getProcAddress(const char *pName)
{ void *p;

if (!(p = ::GetProcAddress(h, pName)))
throwSystemException(
GetLastError(),
_T("GetProcAddress()"));
return p;
}
inline operator HINSTANCE (void)
{ return h;
}
inline HINSTANCE getHINSTANCE(void)
{ return h;
}
};


template<class T, const IID *_piREFIID>
class CPCoCreateInstance
{ private:
T *m_p;
public:
inline CPCoCreateInstance(
REFCLSID _iCLSID,
IUnknown *_pUnkOuter,
DWORD _iClsContext)
{ HRESULT iRet;

m_p = 0;
if (FAILED(iRet = CoCreateInstance(_iCLSID, _pUnkOuter, _iClsContext, *_piREFIID, (void**)&m_p)))
throwSystemException(iRet, _T("CoCreateInstance()"));
if (!m_p)
throwSystemException(E_FAIL, _T("CoCreateInstance()"));
}
inline ~CPCoCreateInstance(void)
{ if (m_p)
m_p->Release();
}
inline operator T *(void)
{ return m_p;
}
inline T *getPtr(void)
{ return m_p;
}
inline T *detach(void)
{ T *pRet = m_p;
m_p = 0;
return pRet;
}
};


class CPCoInitializeEx
{ private:
public:
inline CPCoInitializeEx(void *_pReserved, DWORD _iFlags)
{ HRESULT iRet;

if (FAILED(iRet = CoInitializeEx(_pReserved, _iFlags)))
throwSystemException(iRet, _T("CoInitializeEx() failed!"));
}
inline ~CPCoInitializeEx(void)
{ CoUninitialize();
}
};
 
A

Andre Kostur

(e-mail address removed) wrote in @d31g2000hsg.googlegroups.com:
Hi
I've a question about constructors and exceptions.
//************************************************************
class CObject
{
public:
// ctor
CObject();
// dtor
~ CObject();

// ... methods
};

CObject::CObject()
{
// 1) if ( FAILED( LoadLibrary(...) )) throw exception1;

// 2) if ( FAILED(CoInitialize( 0 )) throw exception2;

// 3) if ( FAILED( CoCreateInstance(....))) throw exception3;
}

CObject::~CObject()
{
// 1) release COM interface

// 2) CoUninitialize();

// 2) FreeLibrary
}

int main(int avgv, char** argc)
{
try{
CObject* ptrObj = new CObject;
}
catch(exception& exc)
{...}
return 0;
}
//****************************************************************
When an error occurs in constructor there is only one way how to say
that samething wrong happen.You can throw an exception but is then a
pointer to CObject valid ?

ptrObj would not have been assigned anything, and in your code would
immediately go out of scope, and thus can not be used anyway.
(Different question: Why are you attempting to new the object anway?
Why not simply declare it as a local variable and then you don't have to
worry about the memory?)
So can you call detructor ~CObject() to release resources. I mean
this : delete ptrObj;

How? There's no way to use ptrObj in the code shown. There's nothing
for you to delete. It won't be used in the try block since the
exception will cause the execution flow to immediately jump to the catch
block, and within the catch block ptrObj is already out of scope and
thus cannot be used.
Is really constructor good place to attach resources (load library or
to get COM interface) ?
I'm not sure.

Sure, but you'd probably want to wrap those in their own RAII classes so
that in the event of them going out of scope, they will dispose of
themselves properly.
I've seen another way. Constructor and destructor are very simple
methods.
All resources are attached in method Initialize and released in
Uninitialize.
These methods can return error codes.

That would be another way. Depends on how you want to use your class.
With the exception-based method you know that your object is always in a
sane and usable state. With the initializtion-based method, your object
has 3 states to worry about: Uninitialized, Initialized, and
Uninitialized but was previously initialized (This might be the same
state as simply Uninitialized).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top