Re: Cpp Considered Harmful
From: Phlip (phlip_cpp_at_yahoo.com)
Date: 08/31/04
- Previous message: Francis Glassborow: "Re: Is export "useless and broken"?"
- In reply to: Steven T. Hatton: "Re: Cpp Considered Harmful"
- Next in thread: Steven T. Hatton: "Re: Cpp Considered Harmful"
- Reply: Steven T. Hatton: "Re: Cpp Considered Harmful"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Date: Tue, 31 Aug 2004 13:01:22 GMT
Steven T. Hatton wrote:
> Kai-Uwe Bux wrote:
>
> > "Read up on them"? Have you ever used this feature? Sometimes you
realize
> > that something is useful not from reading about it.
>
> There has to be some need I have before I look for something to fill it.
> The idea of aborting a program on failure is simply not something I
believe
> to be a good practice.
In a softer language, array[x] throws an exception for you if x is out of
bounds. In a C language, you have the option to either cross your fingers
and do nothing, override [] and throw an exception, or override [] and
provide an assertion that only compiles without NDEBUG activated.
The C languages need the ability to do nothing, or conditionally compile an
exception, to compete with assembly language.
(BTW, if you are not competing with assembly language, _don't use C++_...)
On the test side, here's an assertion:
#define CPPUNIT_ASSERT_EQUAL(sample, result) \
if ((sample) != (result)) { stringstream out; \
out << __FILE__ << "(" << __LINE__ << ") : "; \
out << #sample << "(" << (sample) << ") != "; \
out << #result << "(" << (result) << ")"; \
cout << out.str() << endl; \
OutputDebugStringA(out.str().c_str()); \
OutputDebugStringA("\n"); \
__asm { int 3 } }
The stringerizer, #, converts an expression into a string, and operator<<
formats the expression's value as a string. The macro inserts both these
strings into a stringstream object. Both cout and OutputDebugStringA() reuse
this object's value.
The result, at test failure time, is this line:
c:\...\project.cpp(56) : "Ignatz"(Ignatz) != name(Ignotz)
<F8> takes us directly to the failing test assert statement. The assertion
provides...
- fault navigation - the editor takes you to the failing line
- expression source reflected into the output
- expression values reflected into the output
- a breakpoint
On a platform descended from the Intel x86 architecture, if you run these
tests from a command line, not the editor, the OS will treat __asm { int 3 }
as a hard error, and it will offer to raise the default debugger.
When NDEBUG is off (what some folk call "Debug Mode"), tests can
aggressively exercise production code, making its internal assertions safer
to turn off.
> Actually Stroustrup goes on to demonstrate an alternative form of
assertion
> which also failed to appeal to me. He uses a template that takes an
> invariant as a parameter. And get this. It throws an exception rather
> than aborting the program. In general that is the kind of thing I was
> talking about, but I simply don't find cluttering my programs with
> debugging code a good idea, nor, in general do I find it useful. I've
> noticed C and C++ programmers new to Java tend to use stuff like if(DEBUG
> {/*...*/} until they realize it really isn't all that useful in that
> context.
Aggressive testing tends to help code right-size its assertions, and
exceptions, and hide them behind minimal interfaces. For example, this loads
a library, pulls a function pointer out of it, and asserts it found the
function:
HMODULE libHandle = LoadLibrary("opengl32.dll");
void (APIENTRY *glBegin) (GLenum mode);
FARPROC farPoint = GetProcAddress(libHandle, "glBegin");
assert(farPoint);
glBegin = reinterpret_cast</something/ *> (farPoint);
// use glBegin() like a function
FreeLibrary(libHandle);
The assert is not the problem here - the /something/ is. It should be this:
glBegin = reinterpret_cast
<
void (APIENTRY *) (GLenum mode)
> (farPoint);
To reduce the risk, and avoid writing the complete type of glBegin() and
every other function we must spoof more than once, we upgrade the situation
to use a template:
template<class funk>
void
get(funk *& pointer, char const * name)
{
FARPROC farPoint = GetProcAddress(libHandle, name);
assert(farPoint);
pointer = reinterpret_cast<funk *> (farPoint);
} // return the pointer by reference
That template resolves the high-risk /something/ for us. It collects
glBegin's target's type automatically, puts it into funk, and reinterprets
the return value of GetProcAddress() into funk's pointer's type. And it
calls assert() (which could be your exception) only once, behind the get()
interface.
Pushing the risk down into a relatively typesafe method permits a very clean
list of constructions for all our required function pointers:
void (APIENTRY *glBegin) (GLenum mode);
void (APIENTRY *glEnd) (void);
void (APIENTRY *glVertex3f) (GLfloat x, GLfloat y, GLfloat z);
get(glBegin , "glBegin" );
get(glEnd , "glEnd" );
get(glVertex3f , "glVertex3f" );
That strategy expresses each function pointer's type-the high risk part-once
and only once. (And note how the template keyword converts statically typed
C++ into a pseudo-dynamic language.)
> For the most part, I've pointed to things you /can/ do with Java and
> you /can't/ do with C++.
And the things we can't do in Java (stringerization, token pasting,
conditional compilation, etc.) you decry as "bad C++ style".
Java was invented because too many programmers not bright enough to use C or
C++ were forced into it by schools and managers. They did not write
'new'-free code, and did not use smart pointers where they needed a 'new'.
So Java's inventors said, "Hey, let's tell everyone we don't permit
pointers. Yeah, that's the ticket, pointers are bad. Oh, also we need to
pass primitives by reference, and we need to store heterogenous arrays, and
we need to declare exceptions at all interfaces," and they ended up doing a
zillion extra things to the language specification that C++ lets you do
_with_ the language.
> How so? By introducing a more elegant, efficient, and effective means of
> managing libraries? I know damn good and well that the Cpp is going to be
> around for the foreseeable future. That doesn't mean I can't criticize
its
> use, and proposed solutions for supporting the same functionality without
> resorting to using it.
Please base that criticism on your direct personal experience, not on
quoting Bjarne.
-- Phlip http://industrialxp.org/community/bin/view/Main/TestFirstUserInterfaces
- Previous message: Francis Glassborow: "Re: Is export "useless and broken"?"
- In reply to: Steven T. Hatton: "Re: Cpp Considered Harmful"
- Next in thread: Steven T. Hatton: "Re: Cpp Considered Harmful"
- Reply: Steven T. Hatton: "Re: Cpp Considered Harmful"
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Relevant Pages
|
|