Exception caught inside a constructor

J

Jarek Blakarz

Hi

The following program throws an exception while allocating "A" object.
Allocation fails. An exception is caught inside "C" constructor.
"C" destructor releases memory for both objects. Segmentation fault
occurs while releasing memory for object "A" since the memory has actually not
been allocated for that object.

Please help me to modify the program to work correctly. I want all exceptions
to be caught inside a "C" constructor and no memory leak should happen.

I am aware that this problem may be solved by wrapping ptrA and ptrB in a smart
pointers but I am not interested in this solution.

Thanks for help.

#include <iostream>

using namespace std;

struct A {
A(void)
{
cout << "A" << endl;
}

~A(void)
{
cout << "~A" << endl;
}

void* operator new(size_t size)
{
cout << "A new" << endl;
throw 10; // allocation fails
return ::eek:perator new(size);
}
};

struct B {
B(void)
{
cout << "B" << endl;
}

~B(void)
{
cout << "~B" << endl;
}
};

struct C {
B *ptrB;
A *ptrA;

C(void)
{
cout << "C" << endl;
try {
ptrB = new B;
} catch(...) {
cout << "new B - exception" << endl;
}
try {
ptrA = new A;
} catch(...) {
cout << "new A - exception" << endl;
}
}

~C(void) {
cout << "~C" << endl;
delete ptrB;
delete ptrA;
}
};

int main(void)
{
try {
C c;
} catch(...) {
cout << "main exception handler" << endl;
}
}
 
V

Victor Bazarov

That isn't exactly what your problem is.


At this point, both ptrB and ptrA are uninialized pointers.
They probably have junk for values.


If those threw, 'new' never returned, and no assignment was made,
so the pointers are still junk.


And here, you pass junk to delete.


You should clear the pointers before anything has a chance of going wrong:

C() : ptrA(0), ptrB(0)
{
// do the c'tor details
}

(Others will now tell you not to use pointers.)

Why?

And why not do

C() : ptrA(new A), ptrB(new B) {}

at all? If the latter throws, the former memory will be deallocated (I
think that's guaranteed by the Standard, let somebody correct me if I'm
wrong), and the object will not have been constructed at all, so no
d-tor shall be called...

V
 
V

Victor Bazarov

Yes, I think this is wrong. The constructed subobjects are destroyed
automatically if there is an exception during the next subobject
construction. However, here the subobject in question is a raw pointer
ptrA, whose destroy is a non-op. The C++ compiler is not so smart (and
should not be!) to figure out how to execute parts of the C destructor
code if something goes wrong during the construction.

That's why it is bad to use pointers.

OK, so I must have confused this situation with some other, like
constructing subobjects or members that have their own overloaded 'new'
operator (or something like that).

Oh well, shows how much experience using pointers I have... So, kids,
either learn to use pointers for those rare moments when you do need to
use them, or find any way not to use them at all, ever. :)

V
 
G

Gerhard Fiedler

Jarek said:
Please help me to modify the program to work correctly. I want all
exceptions to be caught inside a "C" constructor and no memory leak
should happen.

Drew showed you one way for this.
I am aware that this problem may be solved by wrapping ptrA and ptrB
in a smart pointers but I am not interested in this solution.

However, IMO this is the better way, even if you don't want to use
standard smart pointers. Rather than having C manage memory for A and B,
have a "memory manager" encapsulate all this. (OTOH, this is more or
less what std::unique_ptr does. You're trying to de-encapsulate what it
does and replicate it "manually" in C. There are reasons why placing
this code into a RAII class is the better choice.)

Gerhard
 
S

Stuart

That isn't exactly what your problem is.
[snip]

You should clear the pointers before anything has a chance of going wrong:

C() : ptrA(0), ptrB(0)
{
// do the c'tor details
}

(Others will now tell you not to use pointers.)

Do not use pointers.

Regards,
Others
 
L

Luca Risolia

Drew said:
You should clear the pointers before anything has a chance of going wrong:

C() : ptrA(0), ptrB(0)
{
// do the c'tor details
}

Some compilers might complain about ptrB being initialized after ptrA, since
ptrB is declared before ptrA.

In C++11 I'd write:

struct C {
B *ptrB = nullptr;
A *ptrA = nullptr;
C() { // ...
 
C

Casey

The following program throws an exception while allocating "A" object.
Please help me to modify the program to work correctly. I want all exceptions
to be caught inside a "C" constructor and no memory leak should happen.

Use smart pointers. Failing that:

#include <iostream>

using namespace std;

struct A {
A(void)
{
cout << "A" << endl;
}

~A(void)
{
cout << "~A" << endl;
}

void* operator new(size_t size)
{
cout << "A new" << endl;
throw 10; // allocation fails
return ::eek:perator new(size);
}
};

struct B {
B(void)
{
cout << "B" << endl;
}

~B(void)
{
cout << "~B" << endl;
}
};

struct C {
B *ptrB;
A *ptrA;

C(void)
{
cout << "C" << endl;
try {
ptrB = new B;
} catch(...) {
cout << "new B - exception" << endl;
throw;
}
try {
ptrA = new A;
} catch(...) {
cout << "new A - exception" << endl;
delete ptrB;
throw;
}
}

~C(void) {
cout << "~C" << endl;
delete ptrB;
delete ptrA;
}
};

int main(void)
{
try {
C c;
} catch(...) {
cout << "main exception handler" << endl;
}
}
 
C

Cholo Lennon

Hi

The following program throws an exception while allocating "A" object.
Allocation fails. An exception is caught inside "C" constructor.
"C" destructor releases memory for both objects. Segmentation fault
occurs while releasing memory for object "A" since the memory has actually not
been allocated for that object.

Please help me to modify the program to work correctly. I want all exceptions
to be caught inside a "C" constructor and no memory leak should happen.

I am aware that this problem may be solved by wrapping ptrA and ptrB in a smart
pointers but I am not interested in this solution.

Thanks for help.

#include <iostream>

using namespace std;

struct A {
A(void)
{
cout << "A" << endl;
}

~A(void)
{
cout << "~A" << endl;
}

void* operator new(size_t size)
{
cout << "A new" << endl;
throw 10; // allocation fails
return ::eek:perator new(size);
}
};

struct B {
B(void)
{
cout << "B" << endl;
}

~B(void)
{
cout << "~B" << endl;
}
};

struct C {
B *ptrB;
A *ptrA;

C(void)
{
cout << "C" << endl;
try {
ptrB = new B;
} catch(...) {
cout << "new B - exception" << endl;
}
try {
ptrA = new A;
} catch(...) {
cout << "new A - exception" << endl;
}
}

~C(void) {
cout << "~C" << endl;
delete ptrB;
delete ptrA;
}
};

int main(void)
{
try {
C c;
} catch(...) {
cout << "main exception handler" << endl;
}
}

You could use a function-try block in your C ctor (in your example B
doesn't throw any exception so you are pretty sure that the caught
exception was raised by A):

....
struct C {
B *ptrB;
A *ptrA;

C()
try
: ptrB(new B)
, ptrA(new A)
{
cout << "C" << endl;
}
catch(int) {
delete ptrB;
}

...
};

int main()
{
try {
C c;
}
catch(int) {
cout << "main exception handler" << endl;
}
}


Regards
 

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

No members online now.

Forum statistics

Threads
473,756
Messages
2,569,535
Members
45,008
Latest member
obedient dusk

Latest Threads

Top