Salt_Peter said:
Kai-Uwe Bux said:
Salt_Peter said:
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.
Where else - in main. Is it not warranted to keep the whole code
exception safe? - not just a lonely ctor?
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