473,403 Members | 2,270 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,403 software developers and data experts.

throw from c'tor

Is there a possibility to create memory leak, the code below if I run
the line:
---------------------------------------------------------
MyClass cl = new MyClass();
---------------------------------------------------------
???

---------------------------------------------------------
MyClass::MyClass()
{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.

But code above has any problem?
thanks!
PS: I worked in C++ for 3 years but after I worked in Java for a 3 years
too. So the returning is a bit hmmm...
Nov 12 '06 #1
24 2340
Chameleon wrote:
Is there a possibility to create memory leak, the code below if I run
the line:
---------------------------------------------------------
MyClass cl = new MyClass();
did you mean:

MyClass * cl = new MyClass();

?
---------------------------------------------------------
???

---------------------------------------------------------
MyClass::MyClass()
{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
delete on a null pointer is OK - no need to do null check.
throw;
}
}
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.

But code above has any problem?
a better idea is to use a vector...

MyClass::MyClass()
{
vector<int> a(X);
vector<int> b(X);
}

.... much easier to read and much harder to get wrong
>

thanks!
PS: I worked in C++ for 3 years but after I worked in Java for a 3 years
too. So the returning is a bit hmmm...
Nov 12 '06 #2

Chameleon skrev:
Is there a possibility to create memory leak, the code below if I run
the line:
---------------------------------------------------------
MyClass cl = new MyClass();
---------------------------------------------------------
???
No.
>
---------------------------------------------------------
MyClass::MyClass()
{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
As Gianni said, it is much better to use a std::vector. It is more
flexibe and just as fast as raw pointers. Most important, however is
that it will "automate" all your work. Copy constructing and assignment
can all be made to work by using the compilers built-in functionality.
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.
There is absolutely nothong wrong about that. On the contrary: it is
the only reasonable way to indicate failure of construction.
[snip]

/Peter

Nov 12 '06 #3

Chameleon wrote:
Is there a possibility to create memory leak, the code below if I run
the line:
---------------------------------------------------------
MyClass cl = new MyClass();
MyClass* p_cl = new MyClass;

or even better:

#include <boost/shared_ptr.hpp>
boost::shared_ptr< MyClass bsp( new MyClass );
---------------------------------------------------------
Why not:

template< typename T >
class MyClass
{
std::vector< T va;
std::vector< T vb;
public:
MyClass() : va(), vb() { }
MyClass(size_t);
};
---------------------------------------------------------
MyClass::MyClass()
template< typename T >
MyClass< T >::Myclass(size_t size) : va(size), vb(size)
{
}
{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.
Nothing wrong with throwing from a ctor, but not like this. catch
explicitly using std::bad_alloc.
>
But code above has any problem?
Yes it does, if the second allocation generates a std::bad_alloc, you
have a leak
Thats why a smart pointer would be preferable.
With vectors, none of this is needed.
>

thanks!
PS: I worked in C++ for 3 years but after I worked in Java for a 3 years
too. So the returning is a bit hmmm...
Nov 12 '06 #4
Salt_Peter wrote:
>
Chameleon wrote:
>Is there a possibility to create memory leak, the code below if I run
the line:
---------------------------------------------------------
MyClass cl = new MyClass();

MyClass* p_cl = new MyClass;

or even better:

#include <boost/shared_ptr.hpp>
boost::shared_ptr< MyClass bsp( new MyClass );
>---------------------------------------------------------
Why not:

template< typename T >
class MyClass
{
std::vector< T va;
std::vector< T vb;
public:
MyClass() : va(), vb() { }
MyClass(size_t);
};
>---------------------------------------------------------
MyClass::MyClass()

template< typename T >
MyClass< T >::Myclass(size_t size) : va(size), vb(size)
{
}
>{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.

Nothing wrong with throwing from a ctor, but not like this. catch
explicitly using std::bad_alloc.
Why? Is there any observable difference?

>>
But code above has any problem?

Yes it does, if the second allocation generates a std::bad_alloc, you
have a leak
No: the catch-handler will be invoked in that case, too; and it will
correctly handle the member array a.
Thats why a smart pointer would be preferable.
Are you be refering to your first suggestion:

shared_ptr< MyClass bsp ( new MyClass );

I think it would not help in a case where the constructor of MyClass leaks:
what is leaked there cannot magically be recovered by the shared_ptr.

With vectors, none of this is needed.
True.

[snip]
Kai-Uwe Bux
Nov 12 '06 #5

Kai-Uwe Bux wrote:
Salt_Peter wrote:

Chameleon wrote:
Is there a possibility to create memory leak, the code below if I run
the line:
---------------------------------------------------------
MyClass cl = new MyClass();
MyClass* p_cl = new MyClass;

or even better:

#include <boost/shared_ptr.hpp>
boost::shared_ptr< MyClass bsp( new MyClass );
---------------------------------------------------------
Why not:

template< typename T >
class MyClass
{
std::vector< T va;
std::vector< T vb;
public:
MyClass() : va(), vb() { }
MyClass(size_t);
};
---------------------------------------------------------
MyClass::MyClass()
template< typename T >
MyClass< T >::Myclass(size_t size) : va(size), vb(size)
{
}
{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.
Nothing wrong with throwing from a ctor, but not like this. catch
explicitly using std::bad_alloc.

Why? Is there any observable difference?
Well yes, from the point of view that the exception thrown is
identifiable.
>
>
But code above has any problem?
Yes it does, if the second allocation generates a std::bad_alloc, you
have a leak

No: the catch-handler will be invoked in that case, too; and it will
correctly handle the member array a.
Yes, thats right, if you handle the deallocation in the catch block as
shown above.
Sorry, my attention span is on the brink.
>
Thats why a smart pointer would be preferable.

Are you be refering to your first suggestion:
no, i was referring to a boost::shared_array for the members.
>
shared_ptr< MyClass bsp ( new MyClass );

I think it would not help in a case where the constructor of MyClass leaks:
what is leaked there cannot magically be recovered by the shared_ptr.

With vectors, none of this is needed.

True.

[snip]
Kai-Uwe Bux
Nov 12 '06 #6
Chameleon wrote:
Is there a possibility to create memory leak, the code below if I run
the line:
---------------------------------------------------------
MyClass cl = new MyClass();
---------------------------------------------------------
???

---------------------------------------------------------
MyClass::MyClass()
{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
The code doesn't even compile. "a" and "b" are local to the
try block; they are not visible outside of those curly braces,
in particular, from within the catch block.

Perhaps you meant to do something such as :

class MyClass
{
int a, b;
MyClass(): a(0), b(0)
{
try {
a = new int[X];
b = new int[X];
}
etc.

in which case the answer is that you will not have a memory
leak because the catch block will free the memory.

It is OK to throw exceptions from constructors; the rule is
that an object is not considered to exist until after its
constructor has completed, so the rest of the program
(assuming you catch the exception) will behave as if the
object never existed.

If you're coming from Java, note that you almost never need
to use "new" and "delete" in C++ ; you should use automatic
memory management (eg. std::vector) wherever possible.
Another Java-ism to avoid is:
MyClass *cl = new MyClass();
(note, the parentheses are redundant here). Better is:
MyClass cl;
and then the object will be automatically destroyed when it
goes out of scope. Unless, of course, you want to manually
manage the lifetime of cl.

Nov 12 '06 #7
Perhaps you meant to do something such as :
>
class MyClass
{
int a, b;
MyClass(): a(0), b(0)
{
try {
a = new int[X];
b = new int[X];
}
etc.
An even better solution would be:

class MyClass
{
int *a, *b;

MyClass() : a( new int[X] ), b( new int[X] )
{}
~MyClass() { delete[] a; delete[] b };
};

If either of the `new int[X]` calls fails then the memory will
automagically be cleaned up. I might be mistaken, but I think I read
that in TC++PL.

Nov 13 '06 #8

drrn wrote:
Perhaps you meant to do something such as :

class MyClass
{
int a, b;
MyClass(): a(0), b(0)
{
try {
a = new int[X];
b = new int[X];
}
etc.

An even better solution would be:

class MyClass
{
int *a, *b;

MyClass() : a( new int[X] ), b( new int[X] )
{}
~MyClass() { delete[] a; delete[] b };
};

If either of the `new int[X]` calls fails then the memory will
automagically be cleaned up. I might be mistaken, but I think I read
that in TC++PL.
You are mistaken. The problem in your code might well be exactly what
the OP is trying to avoid. An object is not constructed until its
constructor finishes executing. Using your code, if I do

MyClass myObject;

then, if b(new int[X]) throws, the construction of myObject has not yet
finished so its destructor is not called during stack unwinding. The
memory pointed to by the member variable a inside the partially
constructed myObject is never freed.

Gavin Deane

Nov 13 '06 #9
Salt_Peter wrote:
Kai-Uwe Bux wrote:
>Salt_Peter wrote:
>>Chameleon wrote:
Is there a possibility to create memory leak, the code below if I run
the line:
---------------------------------------------------------
MyClass cl = new MyClass();
MyClass* p_cl = new MyClass;

or even better:

#include <boost/shared_ptr.hpp>
boost::shared_ptr< MyClass bsp( new MyClass );

---------------------------------------------------------
Why not:

template< typename T >
class MyClass
{
std::vector< T va;
std::vector< T vb;
public:
MyClass() : va(), vb() { }
MyClass(size_t);
};

---------------------------------------------------------
MyClass::MyClass()
template< typename T >
MyClass< T >::Myclass(size_t size) : va(size), vb(size)
{
}

{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.
Nothing wrong with throwing from a ctor, but not like this. catch
explicitly using std::bad_alloc.
Why? Is there any observable difference?

Well yes, from the point of view that the exception thrown is
identifiable.
How does that change the behavior of the program in any way? In the case
of int, no other exception could be thrown, but imagine if the code
changes to use some other type. With the catch(...), the code will still
function, and there will be no leak. If, on the other hand, you catch
bad_alloc specifically, and some other exception is thrown, the code
*will* leak.
--
Clark S. Cox III
cl*******@gmail.com
Nov 13 '06 #10
drrn wrote:
>Perhaps you meant to do something such as :

class MyClass
{
int a, b;
MyClass(): a(0), b(0)
{
try {
a = new int[X];
b = new int[X];
}
etc.

An even better solution would be:

class MyClass
{
int *a, *b;

MyClass() : a( new int[X] ), b( new int[X] )
{}
~MyClass() { delete[] a; delete[] b };
};
Or:

class MyClass
{
std::vector<inta, b;

MyClass() : a(X), b(X) {}

};

--
Clark S. Cox III
cl*******@gmail.com
Nov 13 '06 #11

drrn wrote:
Perhaps you meant to do something such as :

class MyClass
{
int a, b;
MyClass(): a(0), b(0)
{
try {
a = new int[X];
b = new int[X];
}
etc.

An even better solution would be:

class MyClass
{
int *a, *b;

MyClass() : a( new int[X] ), b( new int[X] )
{}
~MyClass() { delete[] a; delete[] b };
};

If either of the `new int[X]` calls fails then the memory will
automagically be cleaned up. I might be mistaken, but I think I read
that in TC++PL.
No, the better solution involves using std::vector members.

Nov 13 '06 #12

Clark S. Cox III wrote:
Salt_Peter wrote:
Kai-Uwe Bux wrote:
Salt_Peter wrote:

Chameleon wrote:
Is there a possibility to create memory leak, the code below if I run
the line:
---------------------------------------------------------
MyClass cl = new MyClass();
MyClass* p_cl = new MyClass;

or even better:

#include <boost/shared_ptr.hpp>
boost::shared_ptr< MyClass bsp( new MyClass );

---------------------------------------------------------
Why not:

template< typename T >
class MyClass
{
std::vector< T va;
std::vector< T vb;
public:
MyClass() : va(), vb() { }
MyClass(size_t);
};

---------------------------------------------------------
MyClass::MyClass()
template< typename T >
MyClass< T >::Myclass(size_t size) : va(size), vb(size)
{
}

{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.
Nothing wrong with throwing from a ctor, but not like this. catch
explicitly using std::bad_alloc.
Why? Is there any observable difference?
Well yes, from the point of view that the exception thrown is
identifiable.

How does that change the behavior of the program in any way? In the case
of int, no other exception could be thrown, but imagine if the code
changes to use some other type. With the catch(...), the code will still
function, and there will be no leak. If, on the other hand, you catch
bad_alloc specifically, and some other exception is thrown, the code
*will* leak.
One would catch a const std::exception&, not bad_alloc.
I'm not saying that would be "better" either.
There is nothing wrong with catch(...) since one can rethrow a relevent
exception.
All i'm saying is that somewhere you'll want to know that a bad_alloc
happened.
So as not to have to investigate an issue that may only occur under
certain extraneous conditions.

Nov 13 '06 #13

Clark S. Cox III wrote:
drrn wrote:
Perhaps you meant to do something such as :

class MyClass
{
int a, b;
MyClass(): a(0), b(0)
{
try {
a = new int[X];
b = new int[X];
}
etc.
An even better solution would be:

class MyClass
{
int *a, *b;

MyClass() : a( new int[X] ), b( new int[X] )
{}
~MyClass() { delete[] a; delete[] b };
};

Or:

class MyClass
{
std::vector<inta, b;

MyClass() : a(X), b(X) {}
public:
MyClass(size_t X) : a(X), b(X) { }
>
};
And yes, the std::vector is both the correct solution and a much more
usefull solution.

Nov 13 '06 #14
Salt_Peter wrote:
>
Clark S. Cox III wrote:
>Salt_Peter wrote:
Kai-Uwe Bux wrote:
Salt_Peter wrote:

Chameleon wrote:
Is there a possibility to create memory leak, the code below if I
run the line:
---------------------------------------------------------
MyClass cl = new MyClass();
MyClass* p_cl = new MyClass;

or even better:

#include <boost/shared_ptr.hpp>
boost::shared_ptr< MyClass bsp( new MyClass );

---------------------------------------------------------
Why not:

template< typename T >
class MyClass
{
std::vector< T va;
std::vector< T vb;
public:
MyClass() : va(), vb() { }
MyClass(size_t);
};

---------------------------------------------------------
MyClass::MyClass()
template< typename T >
MyClass< T >::Myclass(size_t size) : va(size), vb(size)
{
}

{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.
Nothing wrong with throwing from a ctor, but not like this. catch
explicitly using std::bad_alloc.
Why? Is there any observable difference?

Well yes, from the point of view that the exception thrown is
identifiable.

How does that change the behavior of the program in any way? In the case
of int, no other exception could be thrown, but imagine if the code
changes to use some other type. With the catch(...), the code will still
function, and there will be no leak. If, on the other hand, you catch
bad_alloc specifically, and some other exception is thrown, the code
*will* leak.

One would catch a const std::exception&, not bad_alloc.
You really would want to catch(...). For instance, if int was replaced by a
template type parameter, anything could be thrown. There is no guarantee
that a client provided type would not throw an int or some such thing.

I'm not saying that would be "better" either.
There is nothing wrong with catch(...) since one can rethrow a relevent
exception.
All i'm saying is that somewhere you'll want to know that a bad_alloc
happened.
Maybe, but where? In the above code, you need to deallocate a and b
anyway, regardless of the reason for why their construction failed. Any
more specific analysis can be postponed (and that is why the catch-handler
rethrows).
So as not to have to investigate an issue that may only occur under
certain extraneous conditions.
Huh?
Best

Kai-Uwe Bux
Nov 13 '06 #15

Kai-Uwe Bux wrote:
Salt_Peter wrote:

Clark S. Cox III wrote:
Salt_Peter wrote:
Kai-Uwe Bux wrote:
Salt_Peter wrote:

Chameleon wrote:
Is there a possibility to create memory leak, the code below if I
run the line:
---------------------------------------------------------
MyClass cl = new MyClass();
MyClass* p_cl = new MyClass;

or even better:

#include <boost/shared_ptr.hpp>
boost::shared_ptr< MyClass bsp( new MyClass );

---------------------------------------------------------
Why not:

template< typename T >
class MyClass
{
std::vector< T va;
std::vector< T vb;
public:
MyClass() : va(), vb() { }
MyClass(size_t);
};

---------------------------------------------------------
MyClass::MyClass()
template< typename T >
MyClass< T >::Myclass(size_t size) : va(size), vb(size)
{
}

{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.
Nothing wrong with throwing from a ctor, but not like this. catch
explicitly using std::bad_alloc.
Why? Is there any observable difference?

Well yes, from the point of view that the exception thrown is
identifiable.

How does that change the behavior of the program in any way? In the case
of int, no other exception could be thrown, but imagine if the code
changes to use some other type. With the catch(...), the code will still
function, and there will be no leak. If, on the other hand, you catch
bad_alloc specifically, and some other exception is thrown, the code
*will* leak.
One would catch a const std::exception&, not bad_alloc.

You really would want to catch(...). For instance, if int was replaced by a
template type parameter, anything could be thrown. There is no guarantee
that a client provided type would not throw an int or some such thing.
Precisely my point.
Then consider:
try
{
// do whatever
}
catch( const std::exception& r_e)
{
std::cerr << "error: " << r_e.what() << std::endl;
// rethrow?
}
catch(...)
{
std::cerr << "error: unexpected" << std::endl;
// rethrow??
}

Forget the deallocation for now. The point here is to give yourself a
chance to figure out what exception is being caught.
>
I'm not saying that would be "better" either.
There is nothing wrong with catch(...) since one can rethrow a relevent
exception.
All i'm saying is that somewhere you'll want to know that a bad_alloc
happened.

Maybe, but where? In the above code, you need to deallocate a and b
anyway, regardless of the reason for why their construction failed. Any
more specific analysis can be postponed (and that is why the catch-handler
rethrows).
Where else - in main. Is it not warranted to keep the whole code
exception safe? - not just a lonely ctor?
>
So as not to have to investigate an issue that may only occur under
certain extraneous conditions.

Huh?
So your program just crashed without a hint on what was thrown, thats
the Huh? You are assuming that a bad_alloc caused it, but thats not
neccessarily so. Relying on the catch(..) block alone got you there.

Nov 13 '06 #16
Salt_Peter wrote:
>
Kai-Uwe Bux wrote:
>Salt_Peter wrote:
>
Clark S. Cox III wrote:
Salt_Peter wrote:
Kai-Uwe Bux wrote:
Salt_Peter wrote:

Chameleon wrote:
Is there a possibility to create memory leak, the code below if I
run the line:
---------------------------------------------------------
MyClass cl = new MyClass();
MyClass* p_cl = new MyClass;

or even better:

#include <boost/shared_ptr.hpp>
boost::shared_ptr< MyClass bsp( new MyClass );

---------------------------------------------------------
Why not:

template< typename T >
class MyClass
{
std::vector< T va;
std::vector< T vb;
public:
MyClass() : va(), vb() { }
MyClass(size_t);
};

---------------------------------------------------------
MyClass::MyClass()
template< typename T >
MyClass< T >::Myclass(size_t size) : va(size), vb(size)
{
}

{
try {
int *a = 0;
int *b = 0;
a = new int[X];
b = new int[X];
} catch (...) {
if (a) delete[] a;
if (b) delete[] b;
throw;
}
}
---------------------------------------------------------

I know, it is not so clever to throw things from a c'tor.
Nothing wrong with throwing from a ctor, but not like this. catch
explicitly using std::bad_alloc.
Why? Is there any observable difference?

Well yes, from the point of view that the exception thrown is
identifiable.

How does that change the behavior of the program in any way? In the
case of int, no other exception could be thrown, but imagine if the
code changes to use some other type. With the catch(...), the code
will still function, and there will be no leak. If, on the other hand,
you catch bad_alloc specifically, and some other exception is thrown,
the code *will* leak.
One would catch a const std::exception&, not bad_alloc.

You really would want to catch(...). For instance, if int was replaced by
a template type parameter, anything could be thrown. There is no
guarantee that a client provided type would not throw an int or some such
thing.

Precisely my point.
Then consider:
try
{
// do whatever
}
catch( const std::exception& r_e)
{
std::cerr << "error: " << r_e.what() << std::endl;
// rethrow?
}
catch(...)
{
std::cerr << "error: unexpected" << std::endl;
// rethrow??
}

Forget the deallocation for now. The point here is to give yourself a
chance to figure out what exception is being caught.
You seem to think, that the code of the OP does not provide such a chance.
>>
I'm not saying that would be "better" either.
There is nothing wrong with catch(...) since one can rethrow a relevent
exception.
All i'm saying is that somewhere you'll want to know that a bad_alloc
happened.

Maybe, but where? In the above code, you need to deallocate a and b
anyway, regardless of the reason for why their construction failed. Any
more specific analysis can be postponed (and that is why the
catch-handler rethrows).

Where else - in main. Is it not warranted to keep the whole code
exception safe? - not just a lonely ctor?
>>
So as not to have to investigate an issue that may only occur under
certain extraneous conditions.

Huh?

So your program just crashed without a hint on what was thrown, thats
the Huh? You are assuming that a bad_alloc caused it, but thats not
neccessarily so. Relying on the catch(..) block alone got you there.
You are missing the point. Consider the templated variation:

template < typename T >
struct X {
T * a;
T * b;
std::size_t l;
X ( std::size_t n )
: a ( 0 )
, b ( 0 )
, l ( n )
{
try{
a = new T [l];
b = new T [l];
}
catch( ... ) {
delete a;
delete b;
throw;
}
}
};

Within the constructor, you have no chance of knowing what causes the
exception (you might guess it's bad_alloc, but it could be the constructor
of T just as well). Also, the constructor of X does not really want to
know. All it can do is clean up the mess it did during construction, i.e.,
deallocate the members a and b. For that purpose, it does not need to
know why construction of these arrays failed. Thus, the catch(...) in the
constructor of X is justified.

Only the client, who knows what T is can know what T might throw. Therefore,
the client should do:

try {
X< MyConcreteType x ( 23 );
}
catch( std::bad_alloc & ) {
}
catch( whatever ) {
}

The point is that the constructor of X is simply not the right place for
specifying which exception to catch.

Now, I will grant you that one could pass a little more detailed information
to the ambient context so that it can distinguish whether a bad_alloc was
thrown from X of from MyConcreteType. However, I do not quite see how to
make sensible use of that additional piece of information.
Best

Kai-Uwe Bux
Nov 13 '06 #17
VJ
Kai-Uwe Bux wrote:
>
You are missing the point. Consider the templated variation:

template < typename T >
struct X {
T * a;
T * b;
std::size_t l;
X ( std::size_t n )
: a ( 0 )
, b ( 0 )
, l ( n )
{
try{
a = new T [l];
b = new T [l];
}
catch( ... ) {
delete a;
delete b;
throw;
}
}
};

Within the constructor, you have no chance of knowing what causes the
exception (you might guess it's bad_alloc, but it could be the constructor
of T just as well). Also, the constructor of X does not really want to
know. All it can do is clean up the mess it did during construction, i.e.,
deallocate the members a and b. For that purpose, it does not need to
know why construction of these arrays failed. Thus, the catch(...) in the
constructor of X is justified.
In this specific code - I see only std::bad_alloc could be thrown

>
Only the client, who knows what T is can know what T might throw. Therefore,
the client should do:

try {
X< MyConcreteType x ( 23 );
}
catch( std::bad_alloc & ) {
}
catch( whatever ) {
}

The point is that the constructor of X is simply not the right place for
specifying which exception to catch.
It is if you want to throw specific exception. For example
class S
{
public:
class P{};

S()
{
throw P();
}
};

>
Now, I will grant you that one could pass a little more detailed information
to the ambient context so that it can distinguish whether a bad_alloc was
thrown from X of from MyConcreteType. However, I do not quite see how to
make sensible use of that additional piece of information.
In this example no, but there might be a function called in the ctor,
which throws another exception. If you catch that exception, who knows
what you can break in you program, or you can hide a bug using catch(...)

Using catch all is bad for next reason:

"Exception handling is often used as the lazy way out of a problem. Not
sure exactly why something is failing intermittently? Don't bother
investigating, just trap the error and keep going. If it's important,
someone else can fix it properly later."

but it has some uses

This is from
http://neil.fraser.name/writing/exception/
I find this text is fun and useful :)
Nov 13 '06 #18
VJ wrote:
Kai-Uwe Bux wrote:
>>
You are missing the point. Consider the templated variation:

template < typename T >
struct X {
T * a;
T * b;
std::size_t l;
X ( std::size_t n )
: a ( 0 )
, b ( 0 )
, l ( n )
{
try{
a = new T [l];
b = new T [l];
}
catch( ... ) {
delete a;
delete b;
throw;
}
}
};

Within the constructor, you have no chance of knowing what causes the
exception (you might guess it's bad_alloc, but it could be the
constructor of T just as well). Also, the constructor of X does not
really want to know. All it can do is clean up the mess it did during
construction, i.e.,
deallocate the members a and b. For that purpose, it does not need to
know why construction of these arrays failed. Thus, the catch(...) in the
constructor of X is justified.

In this specific code - I see only std::bad_alloc could be thrown
Wrong: the lines

a = new T [l];
b = new T [l];

attempt to not only allocate memory for two arrays (which could fail
throwing the bad_alloc) but also to construct 2l objects of type T. If the
constructor of T for one of these 2l object throws something, then this
something will be caught and rethrown in the catch handler.

[snip]
>Now, I will grant you that one could pass a little more detailed
information to the ambient context so that it can distinguish whether a
bad_alloc was thrown from X of from MyConcreteType. However, I do not
quite see how to make sensible use of that additional piece of
information.

In this example no, but there might be a function called in the ctor,
which throws another exception. If you catch that exception, who knows
what you can break in you program, or you can hide a bug using catch(...)
True: in a different code in the try-block, catch(...) could be bad. Note
that nobody in this thread says that catch(...) is always or even generally
a good idea. We are talking about very specific code.

[snip]

Best

Kai-Uwe Bux
Nov 13 '06 #19
VJ wrote:
Kai-Uwe Bux wrote:
>>
You are missing the point. Consider the templated variation:

template < typename T >
struct X {
T * a;
T * b;
std::size_t l;
X ( std::size_t n )
: a ( 0 )
, b ( 0 )
, l ( n )
{
try{
a = new T [l];
b = new T [l];
}
catch( ... ) {
delete a;
delete b;
throw;
}
}
};

Within the constructor, you have no chance of knowing what causes the
exception (you might guess it's bad_alloc, but it could be the
constructor
of T just as well). Also, the constructor of X does not really want to
know. All it can do is clean up the mess it did during construction,
i.e.,
deallocate the members a and b. For that purpose, it does not need to
know why construction of these arrays failed. Thus, the catch(...) in the
constructor of X is justified.

In this specific code - I see only std::bad_alloc could be thrown
Really? What if MyConcreteType is defined like so:

struct MyConcreteType
{
MyConcreteType() { throw 42; }
};
>>
Only the client, who knows what T is can know what T might throw.
Therefore,
the client should do:

try {
X< MyConcreteType x ( 23 );
}
catch( std::bad_alloc & ) {
}
catch( whatever ) {
}

The point is that the constructor of X is simply not the right place for
specifying which exception to catch.

It is if you want to throw specific exception. For example
class S
{
public:
class P{};

S()
{
throw P();
}
};

>>
Now, I will grant you that one could pass a little more detailed
information
to the ambient context so that it can distinguish whether a bad_alloc was
thrown from X of from MyConcreteType. However, I do not quite see how to
make sensible use of that additional piece of information.

In this example no, but there might be a function called in the ctor,
which throws another exception. If you catch that exception, who knows
what you can break in you program,
Tell me one thing that could be broken by this use of "catch(...)".
or you can hide a bug using catch(...)
Not if you rethrow it. In this constructor the *only* reaswon for
catching an exception is to delete the pointers and rethrow. In this
case, *every* exception should be treated in exactly the same manner.
When that is true (i.e. that the response to every exception is the
same) then catch(...) is the correct response.
Using catch all is bad for next reason:

"Exception handling is often used as the lazy way out of a problem. Not
sure exactly why something is failing intermittently? Don't bother
investigating, just trap the error and keep going. If it's important,
someone else can fix it properly later."

but it has some uses

This is from
http://neil.fraser.name/writing/exception/
I find this text is fun and useful :)

--
Clark S. Cox III
cl*******@gmail.com
Nov 13 '06 #20
* Clark S. Cox III:
VJ wrote:
>or you can hide a bug using catch(...)

Not if you rethrow it.
Depends what "hide a bug" means. If a debugger or the program's run
time library catches an uncaught exception and reports its origin, then
the origin might be reported as the last rethrow site instead of the
original site, with the original throw's program state lost. Another
example is that a certain popular compiler has historically defaulted to
using a language extension where catch(...) catches non-C++ exceptions
that typically signal a botched program state (e.g. division by zero,
nullpointer dereferencing, stack overflow), in that state cleanup code
in such a catch(...) may indeed hide the bug completely, whereas without
the catch(...) one would have an uncaught non-C++ exception.

For only standard C++, without practical considerations such as those
above, I'm not sure whether catch(...) with rethrow can hide a bug. One
vague argument that it probably can't is that the device is used
extensively in one of the most popular implementations of the standard
library. One vague argument that it can is that as I recall that usage
has been criticized, but I don't recall exactly what the critique was.

Generally it's better to use RAII -- cleaning up via destructors --
than catch(...). One exception is where general exception translation
based on a nested rethrow-and-catch is employed: that can't be easily
expressed without catch(...). Another exception is at the top level of
a program or thread, assuming that the end-user doesn't have a debugger.

--
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Nov 13 '06 #21
VJ
Clark S. Cox III wrote:
VJ wrote:
>>Kai-Uwe Bux wrote:
>>>You are missing the point. Consider the templated variation:

template < typename T >
struct X {
T * a;
T * b;
std::size_t l;
X ( std::size_t n )
: a ( 0 )
, b ( 0 )
, l ( n )
{
try{
a = new T [l];
b = new T [l];
}
catch( ... ) {
delete a;
delete b;
throw;
}
}
};

Within the constructor, you have no chance of knowing what causes the
exception (you might guess it's bad_alloc, but it could be the
constructor
of T just as well). Also, the constructor of X does not really want to
know. All it can do is clean up the mess it did during construction,
i.e.,
deallocate the members a and b. For that purpose, it does not need to
know why construction of these arrays failed. Thus, the catch(...) in the
constructor of X is justified.

In this specific code - I see only std::bad_alloc could be thrown


Really? What if MyConcreteType is defined like so:

struct MyConcreteType
{
MyConcreteType() { throw 42; }
};

>>>Only the client, who knows what T is can know what T might throw.
Therefore,
the client should do:

try {
X< MyConcreteType x ( 23 );
}
catch( std::bad_alloc & ) {
}
catch( whatever ) {
}

The point is that the constructor of X is simply not the right place for
specifying which exception to catch.

It is if you want to throw specific exception. For example
class S
{
public:
class P{};

S()
{
throw P();
}
};


>>>Now, I will grant you that one could pass a little more detailed
information
to the ambient context so that it can distinguish whether a bad_alloc was
thrown from X of from MyConcreteType. However, I do not quite see how to
make sensible use of that additional piece of information.

In this example no, but there might be a function called in the ctor,
which throws another exception. If you catch that exception, who knows
what you can break in you program,


Tell me one thing that could be broken by this use of "catch(...)".

Lets say for example you want to throw 42 when a file you want to open
is missing. If you catch this throw like this, you will have no idea
what went wrong, and other parts of your program will behave strangely.
On the other hand, if you do not catch it, your program will crash but
you will get a message why (unhandled exception).
Off course that exception should get caught somewhere else:
try
{
X< MyConcreteType inst1;
}
catch( int &number)
{
if ( 42 == number )
{
cout<<"missing file"<<endl;
}
}

BTW I wouldnt throw numbers like that
Nov 13 '06 #22
VJ
Kai-Uwe Bux wrote:
VJ wrote:

>>Kai-Uwe Bux wrote:
>>>You are missing the point. Consider the templated variation:

template < typename T >
struct X {
T * a;
T * b;
std::size_t l;
X ( std::size_t n )
: a ( 0 )
, b ( 0 )
, l ( n )
{
try{
a = new T [l];
b = new T [l];
}
catch( ... ) {
delete a;
delete b;
throw;
}
}
};
>
True: in a different code in the try-block, catch(...) could be bad. Note
that nobody in this thread says that catch(...) is always or even generally
a good idea. We are talking about very specific code.
Ok, in that case I agree :)

This class is ok, cause you rethrow
Nov 13 '06 #23
VJ wrote:
Clark S. Cox III wrote:
>VJ wrote:
>>>
In this example no, but there might be a function called in the ctor,
which throws another exception. If you catch that exception, who knows
what you can break in you program,


Tell me one thing that could be broken by this use of "catch(...)".

Lets say for example you want to throw 42 when a file you want to open
is missing. If you catch this throw like this, you will have no idea
what went wrong, and other parts of your program will behave strangely.
No, they won't, as the exception was re-thrown. Other code will still
have to catch the exception themselves. I am beginning to sense that you
do not understand what a throw statement without a parameter does. Try
running the following, and you will see that even with the catch(...),
no information is lost, nor is there any trouble discerning what went wrong.

#include <iostream>
using namespace std;

void foo()
{
try
{
throw 42;
}
catch(...)
{
cout << "Caught some exception, re-throwing\n";
/* This throw will re-throw whatever was caught */
throw;
}
}

int main()
{
try
{
foo();
}
catch(int i)
{
cout << "Caught: " << i << endl;
}
return 0;
}

On the other hand, if you do not catch it, your program will crash but
you will get a message why (unhandled exception).
Off course that exception should get caught somewhere else:

try
{
X< MyConcreteType inst1;
}
catch( int &number)
{
if ( 42 == number )
{
cout<<"missing file"<<endl;
}
}
Yes, but for this to not leak, the catch(...) block is needed inside X's
constructor.
BTW I wouldnt throw numbers like that
Nor would I, but generic code has to be prepared for it.
--
Clark S. Cox III
cl*******@gmail.com
Nov 13 '06 #24

Clark S. Cox III wrote in message <12*************@corp.supernews.com>...
>VJ wrote:
>On the other hand, if you do not catch it, your program will crash but
you will get a message why (unhandled exception).
Add:
Don't forget about:
set_terminate( Thandler );
set_unexpected( Uhandler );

--
Bob R
POVrookie
Nov 13 '06 #25

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: Jakob Bieling | last post by:
Hi, Recently, I have seen code where the assignment operator has a return type 'void'. I do understand that it is a 'bad idea' in the sense that I am limiting myself, when using that operator=...
8
by: Protoman | last post by:
#include <iostream> #include <cstdlib> #include <cmath> #include "SmrtPtr.hpp" using namespace std; struct Data { double plus; double mult;
4
by: Tony Johansson | last post by:
Hello! I have a class definition called MyClass see below. I create an instance of this class MyClass I also want this instance to be able to modify the test instance that exist in this...
6
by: tony | last post by:
Hello! When exactly is it important or advisable to use this form load event handler compare to using the C-tor. For example here I create an event handler called dataBoundGridForm that is...
7
by: dick | last post by:
in the "try{throw}catch" structure, how the C++ code return the "type" thrown by a function?
3
by: Chameleon | last post by:
-------------------------------- class A { int data; public: A() { throw; } }; int main(int, char**) { try { A *a = new A;
15
by: Victor Bazarov | last post by:
Hello, Take a look at this program: ----------------------------------- class B { B(const B&); B& operator=(const B&); public: B(int);
2
by: Zytan | last post by:
When you create a Windows app, you get a two files pre-made each with a partial class of the same class, and you also get a c'tor of your class which calls InitializeComponent(). I guess this is...
3
by: RainBow | last post by:
I understand that a compiler synthesises a default constructor if none is provided by the user ( of course depending on the situation if synthesis of such c'tor is actually needed in the program...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.