> What is proper exception handling? I should derive my own exception class from the standard one named
Not necessarily. You could throw
std::overflow_error
or
std::invalid_argument
.
And ideally catch them by reference to const.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
|
try
{
// ...
}
catch( const std::overflow_error& o )
{
// handle overflow
}
catch( const std::exception& e )
{
// handle other errors
}
|
> Where are potentially dangerous places in such class to throw an exception?
In the normal case, in destructors, move constructors or move assignment operators.
However, if you hold raw resources, everywhere.
> What useful overloaded operators along with operator+ or operator- should I embed into my class?
Other than conversion operators, only those operators where you want to intercept and check for errors (overflow etc) are required. For example:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
|
#include <iostream>
#include <memory>
#include <stdexcept>
template< typename T > struct wrapper
{
wrapper( const T& v = T() ) : p( new T(v) ) {}
explicit wrapper( T*&& pp ) : p(pp) { if(!p) throw std::invalid_argument( "nullptr!" ) ; }
// ...
operator T& () { if(!p) throw std::domain_error( "dereference of nullptr!" ) ; return *p ; }
operator const T& () const { if(!p) throw std::domain_error( "dereference of nullptr!" ) ; return *p ; }
// ...
std::unique_ptr<T> p ;
};
int main()
{
wrapper<double> d1(23.4), d2( new double(5.8) ) ;
std::cout << d1 * d2 << '\n' ;
}
|