Helpful Information
 
 
Category: C Programming
[C++] try, catch, throw and destructors

Hi, I'm just venturing into error handling in C++ as I try to learn the language, and I had more of a question rather than a problem.

Scenario: I have a very trivial program that first assigns integers to an array, then tries to print them out from a for loop, with the loop purposely going over the array bounds. I handle the error by throwing an exception as an xBoundary class, which I create to hold data about the error.

Implementation: Just for kicks, I made an actual implementation of the the xBoundary class constructors/desctructor, and had them print out a message so I could see what's happening, and where the class is destroyed. Then I noticed that although only one instance of an xBoundary is created, 3 calls to the destructor are made. I also noticed that on each call to the destructor, the class is not actually destroyed, since the data remains when the next call to the destructor is made.

Question: Why are 3 desctructors being called? The code is below, and for simplicity sake, is all in the same file.



#include <iostream>

class xBoundary
{
public:
// constructors
xBoundary();
xBoundary(const int index);
~xBoundary();

// accessor
int ErrIndex() const {return myIndex;}

private:
int myIndex;
};

// implementations
// The constructors merely print out a message
// indicating they have bee called, along with
// the value of their myIndex property.
xBoundary::xBoundary():
myIndex(-1)
{
std::cout << "xBoundary() -> myIndex=" << myIndex << "\n";
}

xBoundary::xBoundary(const int index):
myIndex(index)
{
std::cout << "xBoundary(const int) -> myIndex=" << myIndex << "\n";
}

xBoundary::~xBoundary()
{
std::cout << "~xBoundary() -> myIndex=" << myIndex << "\n";
}

int main()
{
const int defaultSize = 10;
const int someOtherNumber = 11;
int myArray[defaultSize];
for (int i = 0; i < defaultSize; i++)
myArray[i] = i;
try
{
for (int i = 0; i < someOtherNumber; i++)
{
if (i >= defaultSize)
throw xBoundary(i);
else
std::cout << "myArray[" << i << "]:\t" << myArray[i] << "\n";
}
}
catch(xBoundary err)
{
std::cout << "Failed to retrieve data at index " << err.ErrIndex() << ".\n";
}
return 0;
}


Are the mulitple destructors just being called as the instance of the xBoundary class would normally fall out of scope (but the exception prevents the object from being destroyed)?

Curious,

-Mike

In most books I've read, the exception handler is usually

catch (xBoundary &err)

You can always use:

catch (xBoundary err)

However, in your case, the exception handler catches by value. Hence, a copy of the original exception object is made, which is why you see two constructors and destructors. If you declare the handler to have a reference to the thrown object, then you'll see the constructor fire up only once. Another way, which is used in a lot of code written by Visual C++ programmers goes like this:



try {
...

if (i >= defaultSize)
throw new xBoundary(i);
...
} catch (xBoundary *err) {
cout << err->ErrIndex();
delete err;
}


In this case, you'll see only one constructor and one destructor message. However, you're responsible for deleting your own thrown exception object.

Interesting. Creating the new xBoundary and using pointers does do what is expected: only a single constructor and destructor are called.

My mistake: newbie forgets about copy constructors.

*sigh*

So much to learn.

well, in your code you had:

catch (xBoundary err)

Now with your code, since you're catching by value, the compiler will create a copy of the original thrown object. It'll use the default copy constructor to copy the values from the old object to the new one. You can verify this by adding your own copy constructor to the object.



class xBoundary
{
public:
// constructors
xBoundary();
xBoundary(const int index);
xBoundary(const xBoundary& src); // Overriding the default copy constructor
~xBoundary();

// accessor
int ErrIndex() const {return myIndex;}

private:
int myIndex;
};

// implementations
// The constructors merely print out a message
// indicating they have bee called, along with
// the value of their myIndex property.
xBoundary::xBoundary():
myIndex(-1)
{
std::cout << "xBoundary() -> myIndex=" << myIndex << "\n";
}


xBoundary::xBoundary(const int index):
myIndex(index)
{
std::cout << "xBoundary(const int) -> myIndex=" << myIndex << "\n";
}

xBoundary::~xBoundary()
{
std::cout << "~xBoundary() -> myIndex=" << myIndex << "\n";
}

// New copy constructor
xBoundary::xBoundary(const xBoundary& src) {
myIndex = src.ErrIndex() + 1;
std::cout << "xboundary(const xBoundary &) " << myIndex << "\n";
}



Notice that in the copy constructor, I'm incrementing the errindex of the original by 1. Try using
catch (xBoundary err)
catch (xBoundary &err)
catch (xBoundary *err)

and observe the differences.

Heh, you must've clicked the reply button before I edited my post.

Thanks for you patience though.

-Mike

No problemo, I'm always glad to help. Besides, answering questions helps me become a better programmer as well :).
You're right about the reply button --- I was replying while you were editing your post.

I'm trying to compile a Vectored Exception Handling example. It doesn't seem to compile in Dev-c++. I keep getting errors on the catch. Any ideas how I can get it to compile?

main.cpp




#include <windows.h>
#include <iostream>
#include <stdio.h>

DWORD MyExceptionHandler(void);
int foo(char *buf);

int main(int argc, char *argv[])
{
HMODULE l;
l = LoadLibrary("msvcrt.dll");
l = LoadLibrary("netapi32.dll");
printf("\n\nHeapoverflow program.\n");
if(argc != 2)
return printf("ARGS!");
foo(argv[1]);
return 0;
}

DWORD MyExceptionHandler(void)
{
printf("In exception handler....");
ExitProcess(1);
return 0;
}

int foo(char *buf)
{
HLOCAL h1 = 0, h2 = 0;
HANDLE hp;

try{
hp = HeapCreate(0,0x1000,0x10000);
if(!hp){
return printf("Failed to create heap.\n");
}
h1 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);

printf("HEAP: %.8X %.8X\n",h1,&h1);

// Heap Overflow occurs here:
strcpy((char *)h1,buf);

// This second call to HeapAlloc() is when we gain control
h2 = HeapAlloc(hp,HEAP_ZERO_MEMORY,260);
printf("hello");
}
catch (MyExceptionHandler())
{
printf("oops...");
}
return 0;
}


Its from here:


https://net-ninja.net/article/2010/Oct/25/heap-overflows-for-humans-101/

Create your own thread drezard, don't piggy back off another. If you want to reference this one, add a link.

Create your own thread drezard, don't piggy back off another. If you want to reference this one, add a link.

Oh sorry. I didn't even realise I'd hit the reply button and not a new thread button. Cheers.










privacy (GDPR)