Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

C++ Smart pointers.

55 views
Skip to first unread message

Jama

unread,
Jul 23, 2003, 11:53:46 AM7/23/03
to
I am using visual studio 6.
I have a small demo app. intended to show how C++ smart
pointers could be used. Specifically, I want to know how
smart pointer destructors are called after program
exception that is handled within the program.

It looks from my debug statements within the program, the
smart pointer destructor is never called and therefore,
the object pointed never deleted.

Here, is the program.

#include "stdafx.h"
#include <stdio.h>

class CAddress
{
public:
CAddress(){ printf("Debug : Address Object
Created.\n");}
virtual ~CAddress(){printf("Debug : Address Object
destroyed.\n");}
};

template<class T>
class CSmartPtr
{
public:
CSmartPtr(T* ptr = NULL);
virtual ~CSmartPtr();
private:
T* m_ptr;
};

template<class T>
CSmartPtr<T>::CSmartPtr(T* ptr):m_ptr(ptr)
{
printf("Debug : SmartPtr Constructor called\n");
}

template<class T>
CSmartPtr<T>::~CSmartPtr()
{

printf("Debug : CSmartPtr Distructor called\n");
delete m_ptr;
}

int main(int argc, char* argv[])
{
printf("Debug : Main function called.\n");

{
int i, j;
i = 1;
try{
CSmartPtr<CAddress> smtObj(new
CAddress());
j = 10/(i-1); // This is intended
to break the program
}catch(...)
{
printf("Debug : exception block
entered.\n");
}


printf("Debug : After End of exception
block.\n");

}// I expect the smart pointer destructor called
here.

printf("Debug : End of Main Function\n");
return 0;
}

I expected debug output like this

Debug : Main function called.
Debug : Address Object Created.
Debug : SmartPtr Constructor called
Debug : CSmartPtr Distructor called
Debug : Address Object destroyed.
Debug : After End of exception block.
Debug : End of Main Function
Press any key to continue

But the output is

Debug : Main function called.
Debug : Address Object Created.
Debug : SmartPtr Constructor called
Debug : exception block entered.
Debug : After End of exception block.
Debug : End of Main Function
Press any key to continue

It seams the try{}catch() statement is not doing anything
other than prevent program crash. I expected after
preventing the program crash, control to return to the
program and destructor of the smart pointer called after
the block it is declared.


Thanks

Carl Daniel [VC++ MVP]

unread,
Jul 23, 2003, 1:06:14 PM7/23/03
to
First a couple comments.

1. It's not good practice to rely on catch(...) to catch hardware exceptions
such as division by zero. This is a dangerous feature that will be removed
in the next version of VC.
2. If you're expecting destructors to run, make sure you're compiling with
/EHa and NOT with /GX or /EHs.

When compiled with /EHa, your code behaves as you expect with VC6+SP5 and
VC7.1 (didn't try VC7).

-cd

Jama

unread,
Jul 23, 2003, 2:53:37 PM7/23/03
to
>.
>

Jama

unread,
Jul 23, 2003, 3:03:00 PM7/23/03
to
Thanks Carl, I am glad I asked the question and after
switching from /GX to /EHa I am getting the destructor
called. But you said " It's not good practice to rely on
catch(...) to catch hardware exceptions"
Are there other methods to catch and recover hardware
exceptions?
Thanks again.
>.
>

Igor Tandetnik

unread,
Jul 23, 2003, 4:04:08 PM7/23/03
to
"Jama" <jc6...@yahoo.com> wrote in message
news:02e301c3514d$09099360$a301...@phx.gbl...

> Are there other methods to catch and recover hardware
> exceptions?

Read about Structured Exception Handling (SEH), __try, __except and
__finally
--
With best wishes,
Igor Tandetnik

"For every complex problem, there is a solution that is simple, neat,
and wrong." H.L. Mencken


Kanon Wood

unread,
Jul 23, 2003, 4:34:54 PM7/23/03
to

>
> Read about Structured Exception Handling (SEH), __try, __except and
> __finally
> --
> With best wishes,
> Igor Tandetnik
>
> "For every complex problem, there is a solution that is simple, neat,
> and wrong." H.L. Mencken
>


My documentation says this is "Microsoft Specific." Is this correct?

If so is there a portable alternative?

-Kanon

Carl Daniel [VC++ MVP]

unread,
Jul 23, 2003, 4:46:24 PM7/23/03
to
Kanon Wood wrote:
>> Read about Structured Exception Handling (SEH), __try, __except and
>> __finally
>> --
>> With best wishes,
>> Igor Tandetnik
>>
>> "For every complex problem, there is a solution that is simple, neat,
>> and wrong." H.L. Mencken
>>
>
>
> My documentation says this is "Microsoft Specific." Is this correct?

Yes it is.

>
> If so is there a portable alternative?

No, there is not.

-cd


Craig Powers

unread,
Jul 24, 2003, 9:47:30 AM7/24/03
to
Jama wrote:
>
> Thanks Carl, I am glad I asked the question and after
> switching from /GX to /EHa I am getting the destructor
> called. But you said " It's not good practice to rely on
> catch(...) to catch hardware exceptions"
> Are there other methods to catch and recover hardware
> exceptions?

_set_se_translator will convert hardware exceptions to C++ exceptions.

--
Craig Powers
MVP - Visual C++

Craig Powers

unread,
Jul 24, 2003, 9:52:12 AM7/24/03
to

Generally, the kinds of things that cause operating system exceptions
are undefined behavior (e.g. almost all access violations). Nothing
that deals with undefined behavior will be portable.

Andy Nikitin

unread,
Jul 24, 2003, 4:51:11 AM7/24/03
to
> 1. It's not good practice to rely on catch(...) to catch hardware
exceptions
> such as division by zero. This is a dangerous feature that will be
removed
> in the next version of VC.

please, tell me where i can find explanation of this position.


Carl Daniel [VC++ MVP]

unread,
Jul 24, 2003, 11:15:38 AM7/24/03
to

Much has been written. I don't have time to look up some references at the
moment, but I'll bookmark this message and if noone else has responded by
this evening, I'll try to find a good discussion of the subject.

If you're up for some google work, try looking for postings by myself, Doug
Harrison or William De Pallo in this newsgroup within the past year.

-cd


William DePalo [MVP VC++ ]

unread,
Jul 24, 2003, 11:39:29 PM7/24/03
to
"Carl Daniel [VC++ MVP]" <cpda...@nospam.mvps.org> wrote in message
news:OGDSxZfU...@TK2MSFTNGP10.phx.gbl...
> Andy Nikitin wrote:
> ...

> > please, tell me where i can find explanation of this position.
> ...

> If you're up for some google work, try looking for postings by myself,
Doug
> Harrison or William De Pallo in this newsgroup within the past year.

Andy:

<disclaimer>
Unlike the majority of my VC++ pals here, I

a) don't own a copy of the C++ standard
b) have never read it
c) am not on the leading edge in terms of my usage of the language

So, take what I say with a grain of salt and keep looking for Doug's and
Carl's posts on the topic.
</disclaimer>

The problem as I see it in mixing and matching the operating system's
structured exceptions (SEs) and C++ exceptions is that it makes it too easy
to mask serious errors in an application. Very serious errors like division
by zero, floating point overflow, access violations, etc are the stuff of
SEs. They are always almost a result of a programming error. And by the time
one is signaled the waters may be poisoned to such an extent that graceful
recovery is impossible.

C++ exceptions are almost always due to more benign causes. For example, a
file I/O class might throw an exception on encountering an end of file.
That's no biggie. But if you use this catch clause "catch (...)" then its
hard to separate the wheat from the chaff.

Nevertheless, SEs do occur all the time in development. And in development
it is very important to locate the bug, find the guilty developer and hound
him until he fixes the problem. To that end, and only to that end, I wrote a
class that translates SEs into C++ exceptions. It can do little more than
report the location and cause of the fault. I wrote it so that I could point
a "developer" at the output and say "fix your damned bug" in the gentlest of
tones. <BSEG>

With it, you can write a catch clause like

catch (Win32Exception e)
{
std::cout << e.toString();

DebugBreak();
}

which may help to diagnose the problem.

If you think it will help you, and if google hasn't turned it up yet, I'll
post it again.

Regards,
Will

Arnaud Debaene

unread,
Jul 25, 2003, 8:30:04 AM7/25/03
to
"William DePalo [MVP VC++ ]" <willd....@mvps.org> wrote in message news:<eYTgC7lU...@TK2MSFTNGP10.phx.gbl>...

> To that end, and only to that end, I wrote a
> class that translates SEs into C++ exceptions. It can do little more than
> report the location and cause of the fault. I wrote it so that I could point
> a "developer" at the output and say "fix your damned bug" in the gentlest of
> tones. <BSEG>
>
> With it, you can write a catch clause like
>
> catch (Win32Exception e)
> {
> std::cout << e.toString();
>
> DebugBreak();
> }
>
> which may help to diagnose the problem.
>
> If you think it will help you, and if google hasn't turned it up yet, I'll
> post it again.

Well, it appears you posted it as an attachement, and attachments
aren't showed by Google. I think it would interest a lot of people
(including myself) if you posted it again.

Arnaud
MVP - VC

William DePalo [MVP VC++ ]

unread,
Jul 25, 2003, 11:01:51 AM7/25/03
to
Bonjour Arnaud,

> Well, it appears you posted it as an attachement, and attachments
> aren't showed by Google. I think it would interest a lot of people
> (including myself) if you posted it again.

D'accord. I've placed the sample inline, below.

Note that for this two work you will need to build with the /EHa option. (If
I recall correctly the 7.x IDE will warn you about that while 6.0 does
not).

That's because the optimizing compiler would see no way in which a C++
exception might be thrown below and will remove the try/catch machinery,
failing to realize that an exception can come from an environment which it
knows nothing about.

Regards,
Will

P.S. I expect word wrap will make a mess of the comment banners that precede
the member functions. :-(

--------------------------------------------------------------------------
Here is a quick hack that forces a division by zero:
--------------------------------------------------------------------------

#include <windows.h>
#include <math.h>
#include <iostream>
#include "Win32Exception.h"

int main(int argc, char **argv)
{
int nZero, nQuotient;
double fZero;

// Enables SEH to C++ exception translation

Win32Exception::enable();

try
{
fZero = sin(0.00);
nZero = (int) fZero;
nQuotient = 1 / nZero;
}

catch (Win32Exception e)
{
std::cout << e.toString();

std::cout << std::endl;
}

// Disables SEH translation

Win32Exception::disable();

return 0;
}

------------------------------------------------------------------------
Here is the header for the Win32Exception class:
------------------------------------------------------------------------

#include <eh.h>
#include <string>

class Win32Exception
{
private:

DWORD dwExcCode;
DWORD dwAddress;

static int tlsIndex;
static char fmt[];
static void sehTranslator(UINT u, LPEXCEPTION_POINTERS pexp);

public:

Win32Exception(DWORD, LPEXCEPTION_POINTERS);
Win32Exception(DWORD, DWORD);
~Win32Exception();

bool static enable(int);
bool static enable(void);
void static disable(void);
DWORD getAddress() const;
DWORD getCode() const;
std::string getType() const;
std::string getModuleName() const;
DWORD getModuleOffset() const;
std::string toString() const;
};

------------------------------------------------------------------------
Here is the source for the Win32Exception class:
------------------------------------------------------------------------

/*************************************************************************
This class enables C++ code to catch Win32 structured exceptions. Its
static member function handle() can be used to specify whether or not
structured exceptions should be handled on a per-thread basis. Where
they are handled a Win32Exception is thrown. The class includes a
toString() function which details the exception. Several other member
functions exist to determine the exception code, the exception type,
the exception address, the name of the module containing the exception
address and the offset from the start of that module to the exception
address.
*************************************************************************/
#include <windows.h>
#include "Win32Exception.h"

/*************************************************************************
For each thread we save the address of the previous SE handler
translator. We make no attempt to maintain a chain of previous handlers.
We assume that we want to translate structured exceptions to C++
exceptions or we want the default behavior.
*************************************************************************/
int Win32Exception::tlsIndex = -1;

/*************************************************************************
Old habits die hard deaths
*************************************************************************/
char Win32Exception::fmt[] = "%08.08X";

/*************************************************************************
The constructor saves the exception code and the address where the
structured exception was encountered.
*************************************************************************/
Win32Exception::Win32Exception(DWORD dwCode, LPEXCEPTION_POINTERS pexp)
{
dwExcCode = dwCode;
dwAddress =
reinterpret_cast<DWORD>(pexp->ExceptionRecord->ExceptionAddress);
}

/*************************************************************************
The constructor saves the exception code and the address where the
structured exception was encountered.
*************************************************************************/
Win32Exception::Win32Exception(DWORD dwCode, DWORD dwLocation)
{
dwExcCode = dwCode;
dwAddress = dwLocation;
}

/*************************************************************************
The destructor doesn't do anything
*************************************************************************/
Win32Exception::~Win32Exception(){}

/*************************************************************************
This is the exception handler translator. We create an instance of the
Win32Exception class and then throw it.
*************************************************************************/
void Win32Exception::sehTranslator(UINT u, LPEXCEPTION_POINTERS pexp)
{
Win32Exception exc(u, pexp);
throw exc;
}

/*************************************************************************
The function enables the translation of structured exceptions to C++
exceptions.
*************************************************************************/
bool Win32Exception::enable(int nIndex)
{
bool ok;
_se_translator_function oldTrans;

if ( tlsIndex == -1 )
tlsIndex = nIndex;

if ( tlsIndex == -1 )
ok = false;

else
{
oldTrans = _set_se_translator(&Win32Exception::sehTranslator);
TlsSetValue(tlsIndex, oldTrans);

ok = true;
}

return ok;
}

/*************************************************************************
The function enables the translation of structured exceptions to C++
exceptions.
*************************************************************************/
bool Win32Exception::enable(void)
{
if ( tlsIndex == -1 )
tlsIndex = TlsAlloc();

return Win32Exception::enable(tlsIndex);
}

/*************************************************************************
The function disables the translation of structured exceptions to C++
exceptions.
*************************************************************************/
void Win32Exception::disable(void)
{
_se_translator_function oldTrans;

if ( tlsIndex != -1 )
{
oldTrans = (_se_translator_function) TlsGetValue(tlsIndex);
_set_se_translator(oldTrans);

TlsSetValue(tlsIndex, 0);
}

return;
}

/*************************************************************************
The function returns the address where the exception occurred.
*************************************************************************/
DWORD Win32Exception::getCode() const
{
return dwExcCode;
}

/*************************************************************************
The function returns the address where the exception occurred.
*************************************************************************/
DWORD Win32Exception::getAddress() const
{
return dwAddress;
}

/*************************************************************************
The function returns the type of exception that occurred.
*************************************************************************/
std::string Win32Exception::getType() const
{
std::string str;

switch ( dwExcCode )
{
case EXCEPTION_ACCESS_VIOLATION:

str = "Access Violation";
break;

case EXCEPTION_DATATYPE_MISALIGNMENT:

str = "Datatype Misalignment";
break;

case EXCEPTION_BREAKPOINT:

str = "Breakpoint";
break;

case EXCEPTION_SINGLE_STEP:

str = "Single Step";
break;

case EXCEPTION_ARRAY_BOUNDS_EXCEEDED:

str = "Array Bounds Exceeded";
break;

case EXCEPTION_FLT_DENORMAL_OPERAND:

str = "Float Denormal Operand";
break;

case EXCEPTION_FLT_DIVIDE_BY_ZERO:

str = "Floating Point Divide by Zero";
break;

case EXCEPTION_FLT_INEXACT_RESULT:

str = "Floating Point Inexact Result";
break;

case EXCEPTION_FLT_INVALID_OPERATION:

str = "Floating Point Invalid Operation";
break;

case EXCEPTION_FLT_OVERFLOW:

str = "Floating Point Overflow";
break;

case EXCEPTION_FLT_STACK_CHECK:

str = "Floating Point Stack Check";
break;

case EXCEPTION_FLT_UNDERFLOW:

str = "Floating Point Underflow";
break;

case EXCEPTION_INT_DIVIDE_BY_ZERO:

str = "Integer Division by Zero";
break;

case EXCEPTION_INT_OVERFLOW:

str = "Integer Overflow";
break;

case EXCEPTION_PRIV_INSTRUCTION:

str = "Privileged Instruction";
break;

case EXCEPTION_IN_PAGE_ERROR:

str = "In Page Error";
break;

case EXCEPTION_ILLEGAL_INSTRUCTION:

str = "Illegal Instruction";
break;

case EXCEPTION_NONCONTINUABLE_EXCEPTION:

str = "Non-continuable Exception";
break;

case EXCEPTION_STACK_OVERFLOW:

str = "Stack Overflow";
break;

case EXCEPTION_INVALID_DISPOSITION:

str = "Invalid Disposition";
break;

case EXCEPTION_GUARD_PAGE:

str = "Guard Page";
break;

case EXCEPTION_INVALID_HANDLE:

str = "Invalid Handle";
break;

default:

str = "Unknown";
break;
}

return str;
}

/*************************************************************************
This function translates the exception to a displayable string.
*************************************************************************/
std::string Win32Exception::toString() const
{
char szAddress[10];
std::string str;

str = "An exception of type 0x";

wsprintf(szAddress, fmt, dwExcCode);
str.append(szAddress);

str.append( " - '");
str.append( getType() );
str.append( "' - occurred at 0x");

wsprintf(szAddress, fmt, dwAddress );
str.append(szAddress);

str.append( " in module '");
str.append( getModuleName() );
str.append( "' at offset 0x");

wsprintf(szAddress, fmt, getModuleOffset() );
str.append(szAddress);

return str;
}

/*************************************************************************
This function returns the name of the file that contains the module
where the exception occurred.
*************************************************************************/
std::string Win32Exception::getModuleName() const
{
int n;
char szModule[_MAX_PATH + 1];
std::string str;
MEMORY_BASIC_INFORMATION mbi;

ZeroMemory(&mbi, sizeof(mbi));

VirtualQuery(reinterpret_cast<const void *>(dwAddress), &mbi, sizeof(mbi));

n = GetModuleFileName( reinterpret_cast<HINSTANCE>(mbi.AllocationBase),
szModule, _MAX_PATH);
if ( n > 0 )
str = szModule;

else
str = "Unknown?";

return str;
}

/*************************************************************************
This function returns the offset from the start of the module to
the instruction where the exception occurred.
*************************************************************************/
DWORD Win32Exception::getModuleOffset() const
{
DWORD dwOffset;
MEMORY_BASIC_INFORMATION mbi;

ZeroMemory(&mbi, sizeof(mbi));

VirtualQuery( reinterpret_cast<const void *>(dwAddress), &mbi,
sizeof(mbi));

dwOffset = dwAddress - reinterpret_cast<DWORD>(mbi.AllocationBase);

return dwOffset;
}


Jama

unread,
Jul 28, 2003, 10:30:56 AM7/28/03
to
Will, thank you very much for posting your code. I have
copied it into a VC++ project but some information has
been lost as a result of copying. For instance the system
hear file names between '<' and '>' has been lost. Also
the reinterpret_cast template types has been lost.
For example. The code you posted shows
VirtualQuery( reinterpret_cast(dwAddress), &mbi,sizeo
(mbi));
I expected something like
VirtualQuery( reinterpret_cast'void*'(dwAddress),
&mbi,sizeo(mbi));
where ' replaces the greater than and the less than sign
to make sure it posts in this news group.

the 'void*' is my best guess as VirtualQuery
expects 'void*'.

I will appriate if you repost only the lines containing
the reinterpret_cast with '<' and '>' replaces something
like ' ot ".
Thanks

>.
>

Jama

unread,
Jul 29, 2003, 9:57:35 AM7/29/03
to
I have looked everywhere in this newsgroup and I can't
find any link that will let me download the attachment
made by William DePalo yesterday.
I will appreciate if anyone can tell me how to locate
attachments in this newsgroup.
If the other participants of this question were able to
locate the attachment, kindly send it to me to my email
if possible. My email is jc6...@yahoo.com.
Thank you all.
Jama


>-----Original Message-----
>"Jama" <jc6...@yahoo.com> wrote in message

>news:081501c35514$db350de0$a501...@phx.gbl...


>> Will, thank you very much for posting your code.
>

>You are welcome.


>
>> I have copied it into a VC++ project but some
information has
>> been lost as a result of copying.
>

>Problem with word wrapping?
>
>I have attached a ZIP containing two source files and a
header. Don't forget
>to build your project with /EHa
>
>Regards,
>Will
>
>
>

Jama

unread,
Jul 29, 2003, 11:49:07 AM7/29/03
to
Bryan Griggs was kind enough to send me the zip files by
William DePalo for this question.
Thanks
Jama
>.
>
0 new messages