exception question,

C

cronusf

I have code like this (pseudocode):

MyClass::MyClass()
{
Array1 = new D3DXVECTOR3[MaxVertexCount];
Array2 = new USHORT[MaxIndexCount];

fx = gcnew Effect();
}

Suppose the constructor for Effect throws an exception. During the
stack unwinding, will Array1 and Array2 be deleted?

I put the delete[] code in the destructor and finalizer, but I noticed
(through trace statements) the destructor and finalizer is never
called. Do I need a try/finally here to make sure the memory is
deleted?
 
C

Carl Daniel [VC++ MVP]

I have code like this (pseudocode):

MyClass::MyClass()
{
Array1 = new D3DXVECTOR3[MaxVertexCount];
Array2 = new USHORT[MaxIndexCount];

fx = gcnew Effect();
}

Suppose the constructor for Effect throws an exception. During the
stack unwinding, will Array1 and Array2 be deleted?

I put the delete[] code in the destructor and finalizer, but I noticed
(through trace statements) the destructor and finalizer is never
called. Do I need a try/finally here to make sure the memory is
deleted?

What's the type of Array1? Array2?

Unless it's some kind of smart pointer that takes care of deleting the
allocated memory, then you need to take responsibility for doing it.

The best option is to use a more intelligent data structure that takes care
of it for you, such as std::vector<D#DXVECTOR3> or std::vector<USHORT>,
rather than a bare pointer. When those objects go out of scope, their
destructors will be called automatically to clean up the memory allocation.

If you're set on handling it yourself instead of using a library component
to do it for you then yes, you need a try/catch around the code to handle
cleanup in the case of an exception thrown from the Effect constructor.

-cd
 
G

Giovanni Dicanio

I have code like this (pseudocode):

MyClass::MyClass()
{
Array1 = new D3DXVECTOR3[MaxVertexCount];
Array2 = new USHORT[MaxIndexCount];

Correct me if I'm wrong, but I think that Array1 and Array2 are defined like
this:

<code>

class MyClass
{
...

D3DXVECTOR3 * Array1;
USHORT * Array2;
...

};

</code>

In that case, the answer to your question is "no": your code is not
exception safe, if an exception is thrown in the constructor, Array1 and
Array2 are leaked.

As Carl already wrote, I think the best approach is to use std::vector
instead of new[] (and delete[]).

e.g.

<code>

#include <vector> // Use std::vector

class MyClass
{
....

std::vector< D3DXVECTOR3 > Array1;
std::vector< USHORT > Array2;

...
};


MyClass::MyClass()
: Array1( MaxVertexCount ), // Construct the std::vector arrays
Array2( MaxIndexCount )
{
... other code
fx = gcnew Effect();
}

</code>

Note that std::vector can change size at run-time (unlike arrays allocated
with new[], which are fixed-size), so you may also want to initialize empty
vectors, and use .push_back() method to add new data to vector.

There is a similar case if you have something like a *raw* pointer to some
class as data member, e.g.:

<code>

class MyClass
{
...
X * pX; // X is some embedded class (raw pointer)
};

MyClass::MyClass()
{
pX = new X(...);
....
}

</code>

The above code is exception unsafe, and if some exception is thrown in the
constructor, the instance of X allocated on the heap is leaked.
You should instead use a smart pointer like shared_ptr in this case:

<code>

class MyClass
{
...
shared_ptr< X > spX; // smart pointer to X
};

MyClass::MyClass()
spX( new X(...) ) // Create new X
{
...
}

</code>

In general, in modern C++, you should use container classes like std::vector
instead of raw arrays (new[]/delete[]), and smart pointers (like shared_ptr)
instead of raw pointers. This will make your programming life easier: you
will have less leaks, and more robust and exception-safe code.

Giovanni
 
C

cronusf

I have code like this (pseudocode):
MyClass::MyClass()
{
Array1 = new D3DXVECTOR3[MaxVertexCount];
Array2 = new USHORT[MaxIndexCount];

Correct me if I'm wrong, but I think that Array1 and Array2 are defined like
this:

<code>

class MyClass
{
...

D3DXVECTOR3 * Array1;
USHORT * Array2;
...

};

</code>

In that case, the answer to your question is "no": your code is not
exception safe, if an exception is thrown in the constructor, Array1 and
Array2 are leaked.

As Carl already wrote, I think the best approach is to use std::vector
instead of new[] (and delete[]).

e.g.

<code>

#include <vector> // Use std::vector

class MyClass
{
....

std::vector< D3DXVECTOR3 > Array1;
std::vector< USHORT > Array2;

...
};

The issue is that this is a managed ref class, so I cannot have that.
I can only have pointers to native types. Having:

std::vector< D3DXVECTOR3 >* Array1;

would still require me to allocate the vector with new.
 

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

Top