K
Kai-Uwe Bux
Zorro said:Kai-Uwe Bux said:Grizlyk said:Simon G Best wrote: [snip]
As usual, C++ does not impose safety on the programmer; instead, it
provides tools to help the programmer write safe code.
In the case of "divide by zero" , we are speaking excactly about that
C++ does not provides tools to help the programmer write safe code. No
tools.
That is not entirely correct: you can write a wrapper template for the
arithmetic types. I confine myself to a rough outline. Also, I will
acknowledge that it is impossible to make such wrappers behave exactly
like the built in types (e.g., with regard to automatic promotions and
conversions). However, in many cases, such a wrapper can be used. E.g.,
for debugging pointers, I do use a smart pointer whose operator* method
does assert( underlying_pointer != 0 ).
#include <stdexcept>
#include <string>
struct divide_by_zero : public std:ut_of_range {
divide_by_zero ( std::string const & msg )
: std:ut_of_range( msg )
{}
}; // divide_by_zero
template < typename ArithmeticType >
struct throw_divide_by_zero {
typedef ArithmeticType base_type;
explicit
throw_divide_by_zero ( base_type x = 0 )
: data ( x )
{}
friend
throw_divide_by_zero operator+ ( throw_divide_by_zero lhs,
throw_divide_by_zero rhs ) {
return ( throw_divide_by_zero( lhs.data + rhs.data ) );
}
// many more friends
// ...
// and finally, division:
friend
throw_divide_by_zero operator/ ( throw_divide_by_zero lhs,
throw_divide_by_zero rhs ) {
if( rhs.data == 0 ) {
throw ( divide_by_zero( std::string( "division by 0" ) ) );
}
return ( throw_divide_by_zero( lhs.data + rhs.data ) );
}
private:
base_type data;
}; // throw_divide_by_zero
#include <iostream>
int main ( void ) {
try {
throw_divide_by_zero<int> a ( 0 );
throw_divide_by_zero<int> b ( 3 );
b / a;
}
catch ( divide_by_zero const & c ) {
std::cout << c.what() << '\n';
}
}
Best
Kai-Uwe Bux
Kai-Uwe, this is nice. However, look at all the code you have written
for something so simple. And you also expect everyone to remember how
to do such things in all cases, possibly in complex situations?
If you have a need for this kind of thing, you write it once and the you
just use it. I do that for pointers. You do not need to re-implement that
every time. That's what library solutions are like.
Another advantage is the flexibility: if I regarded division by 0 a bug, I
could use an assert instead of a throw. I could even make that a policy
passed as a template parameter. If you put a mechanism into the core
language, you have a "one-size-fits-all" approach.
I am not entering the discussion.
We shall see about that. It appears a though you might have something to
say.
I was just wondering if you thought about your extensive creativity.
There is nothing extensive about the creativity in the code sample shown
above. The problem is fairly straight forward: the built-in types of C++
make virtually no guarantees towards enforcing preconditions of operations.
Thus, if you need types that do, you have to provide them yourself. That is
where the extensible type system of C++ comes in as the tool that the
language provides to help with these issues.
Other languages are designed differently. They may provide different means
of writing safe code. It is, however, not fair to claim that C++ does not
provide tools/mechanisms to ease safe coding.
Best
Kai-Uwe Bux