Why do some code bases don't use exceptions?

D

dragan

James said:
James said:
James Kanze wrote:
"dragan" ha scritto nel
[....]
That's the whole point of exceptions. They're for the sort of
problems where it doesn't matter where the problem occured; the
handling is the same. If you run out of memory processing a
request, for example, it doesn't matter where you were in the
processing when you ran out; you just abort the request (but not
the process) with an error message, and continue.
You seem to be big on aborting.
Attention about word use. There's aborting (in the sense of
calling abort()), and aborting (in the more general sense,
of immediately terminating some action that you were in the
process of doing). In this case, I'm using the other sense:
say you've received a request on your LDAP server, and you
run out of memory trying to service it (because it requires
interpreting some obscenely complicated filter expression,
for example). When you detect the lack of memory, you're
down in some really deap parsing function, executing
operator new. You (or rather the system) raises an
std::bad_alloc exception, which you catch at the top level,
and abort the request (not the program), returning an error
message of "insufficient resources", or the like.
Ah. Bad choice of word then to describe that.

I didn't invent the language (English). I just use it.

Don't worry about. It's my "second language", but maybe that elicited me to
study it more. I have found no error in you use of English.
I don't
know of any other word for what I described; abort is the
standard word.

It sounds like an "unstudied appropriation". "Hurried". Inappropriate and
incorrect.
I think most people read more than just a word at a time,

Oh, you know I'm not gonna let you off that easy Mr. (Did you read where I
was spanking the other with such childish tactic? Did he maybe LEARN it from
you??!)
and
the expression "abort the request" is quite clear. "Abort the
request" is not "abort the process".

Noted: your vocabulary is terse so you requisition what you have at your
disposal, hoping that it will be understood (or hoping it will give you a
scapegoat!). I understand the way you think. You are unsure of what to do.
And so, unsure of yourself. But, you KNOW that you can be MORE or "the
bomb". Let's get it done. You're really Elvis, right? I mean really, you
can't hide forever right? Surely you are Elvis. The King!

:/ <-- parse this.
I'm not sure I follow. The server will certainly have some
resources preallocated, so that it can successfully log the
error, unwind the stack, and return an error message.

Pfft. Stop already. To cut the convo short: I think I can deploy without C++
exceptions. Any of this "large scale" bullshit, does not apply to me, so
curb it already. Stop being pedantic. (Or not, it's all good: it's my fault
if I get sucked into these USELESS tiradal "discussions").
But by
definition, it can't use those resources for parsing the
request, or they won't be available for the things they were
reserved for.

Answer: too abstract. I have a real application and don't need to be
thinking about "THE general solution" that will do this that AND cure cancer
as a side effect. Nuff said. If you don't grok that, I don't care, you're
not my problem.
Which one? Are you saying that if you get std::bad_alloc, you
should output a message to the terminal, asking the sysop to
insert additional memory chips, and only continue when he does?

I could call you facetious, but I think you trully are not following the
main points. Your scapegoat is that you follow too many threads. I said
"preallocate", but just like I said that error handling (not "management"
this time) is application-specific, so is that one specific error. I know
those answers. I don't want to entertain discussion or be the bouncing board
for those who only "read the books". No offense, but it's not my thing. And
no, I'm not being "high and mighty", nor am I about to be a whimp. (speaking
of whimps, I noticed you didn't have anything more to say about being WRONG
about "error reporting"). :) :p
Preallocate what?
M-E-M-O-R-Y.

Parsing an LDAP request requires unbounded

You don't really expect me graft my discussion on your post-conceived
scenario, do you? That would be so "unsporting".
memory, since the request can be arbitrarily complicated: the
filter expression can contain any number of parenthesized
sub-expressions. It's just like a C or a C++ compiler: feed it
a file with a function which contains 2 billion nested
parentheses, and see what happens. You can't predict up front
how complex an expression will be, and how much memory you'll
need. Either you arbitrarily limit the complexity (for example,
to prevent stack overflow if you're using recursive descent), or
you handle insufficient memory. Or both: you might normally be
able to handle the expression, but not if a thousand or so
clients send it at the same time.

So, maybe "call me" when you have a PRODUCT like SmartHeap? Else maybe "shut
up"? You don't really think I'd consider hiring you before I'd buy a product
like that, do you? I do it differently, yes. Internally I DO "compete" with
the commercial memory allocator offerings. No offense meant.

Dragan
"English is my second language" :)
 
P

peter koch

It wasn't an example.


Or how to make people THINK? I mean, you're thinking about it, right?
Success.



?? You can't see the "return OK;" statement??

I was referring to the std::string that was the result of the
computation.
?? You can't see the "return ERROR;" statement?
You are assuming that you can only have one kind of error? In real
life more than one thing can go wrong, the reason being kept in the
return code. That is why you use an int, not a bool.
You "got me": I had to stick in the baggage from the previous poster's
example: std::string. Touche, and: :p. If you were REALLY smart though,
you'd ask, "why is this dude who is avoiding exceptions using
std::string??!". Answer: he wouldn't.

You are welcome to use your own class if that would simplify things.

You forgot to comment about this point.

And this one as well.

And also on this one.
If you like Humvees, but they only were available in pink, maybe you'd
repaint it? Some people would just buy something else. Oh, there IS NOTHING
ELSE you say? Don't be so sure. Is that a corporate Vee you're driving?
Dude, nice COLOR! (hehehe).

I fail to see the analogy. The Humvee is your code - using six lines
of code (plus the macroes) where one suffices, and introducing
unsustainable elements (the hidden gotos as a potential source of ill-
formed code).

/Peter
 
J

James Kanze

James said:
James Kanze wrote:
James Kanze wrote:
"dragan" ha scritto nel
[....]
That's the whole point of exceptions. They're for the
sort of problems where it doesn't matter where the
problem occured; the handling is the same. If you run
out of memory processing a request, for example, it
doesn't matter where you were in the processing when you
ran out; you just abort the request (but not the
process) with an error message, and continue.
You seem to be big on aborting.
Attention about word use. There's aborting (in the sense
of calling abort()), and aborting (in the more general
sense, of immediately terminating some action that you
were in the process of doing). In this case, I'm using
the other sense: say you've received a request on your
LDAP server, and you run out of memory trying to service
it (because it requires interpreting some obscenely
complicated filter expression, for example). When you
detect the lack of memory, you're down in some really deap
parsing function, executing operator new. You (or rather
the system) raises an std::bad_alloc exception, which you
catch at the top level, and abort the request (not the
program), returning an error message of "insufficient
resources", or the like.
Ah. Bad choice of word then to describe that.
I didn't invent the language (English). I just use it.
Don't worry about. It's my "second language", but maybe that
elicited me to study it more. I have found no error in you use
of English.
It sounds like an "unstudied appropriation". "Hurried".
Inappropriate and incorrect.

It is the standard word for this. The C function takes its name
from everyday usage: to abort an action is to terminate it
bruskly. In transaction terminology, it's frequent to speak of
aborting a transaction (which results in a roll-back instead of
a commit); in server technology, it's frequent to speak of
aborting a request. And so on. The C function aborts the
process, but processes are far from the only things which can be
aborted.
Oh, you know I'm not gonna let you off that easy Mr. (Did you
read where I was spanking the other with such childish tactic?
Did he maybe LEARN it from you??!)
Noted: your vocabulary is terse so you requisition what you
have at your disposal, hoping that it will be understood (or
hoping it will give you a scapegoat!).

Sorry, but in this context, "abort" is the standard word, and
has been pretty much everywhere I've worked. It's also been the
word I've seen used in literature.
I understand the way you think. You are unsure of what to do.
And so, unsure of yourself.

You're the first person who's accused me of that:). I'm
usually accused of being too sure of myself.

[...]
I could call you facetious, but I think you trully are not
following the main points. Your scapegoat is that you follow
too many threads. I said "preallocate", but just like I said
that error handling (not "management" this time) is
application-specific, so is that one specific error.

Yes, but I presented a very specific case: parsing an LDAP
request. An LDAP request can be arbitrarily complex, and can
require an arbitrarily large amount of memory. How do you
"pre-allocate" an arbitrary large amount of memory? No matter
how much you pre-allocate, it might not be enough.

[...]
You don't really expect me graft my discussion on your
post-conceived scenario, do you? That would be so
"unsporting".

In other words, you prefer to ignore issues that you don't
understand.
 
J

Joshua Maurice

Notoriously slow is a pretty vague statement.  Exceptions do not slower
the speed of the code unless they are thrown.  So your choices are: slow
your happy code (that runs a billion times) by inserting hundreds of if
statements into it to propagate return codes up the call stack to the
handler, or make returning 1000 times slower 3 times a day...  It is a
no brainer to me.

Sadly no. That was the intent. However, on half of all of the unix-
like environments available for me to test on, including Solaris, AIX,
HPUX, Linux, and for the common windows platforms, win32, win64,
exceptions add overhead even when not thrown, some worse than others.
Windows, for example, implements C++ exceptions on top of their
structured exception handling, which means that you're paying a
penalty every time you enter a try block. For a particularly contrived
test I once wrote, I got performance slowdowns of up to ~1.5x slower
than the version which used error return codes on one platform.

Not that I'm trying to say use exceptions or don't in this post. Just
understand their practical costs and don't repeat (wishful)
misinformation.
 
I

Ian Collins

Joshua said:
Sadly no. That was the intent. However, on half of all of the unix-
like environments available for me to test on, including Solaris, AIX,
HPUX, Linux, and for the common windows platforms, win32, win64,
exceptions add overhead even when not thrown, some worse than others.
Windows, for example, implements C++ exceptions on top of their
structured exception handling, which means that you're paying a
penalty every time you enter a try block. For a particularly contrived
test I once wrote, I got performance slowdowns of up to ~1.5x slower
than the version which used error return codes on one platform.

Not that I'm trying to say use exceptions or don't in this post. Just
understand their practical costs and don't repeat (wishful)
misinformation.

How have you measured? All my tests on Solaris with gcc and Sun CC have
shown the normal execution path to be faster with exceptions than
testing return values.
 
J

Joshua Maurice

How have you measured?  All my tests on Solaris with gcc and Sun CC have
shown the normal execution path to be faster with exceptions than
testing return values.

My tests on Sun 64 with gcc also show that the implementation uses the
"correct" aka "good" aka table approach to implementing exceptions,
resulting in (near) zero overhead. (Sun on x86 is another story.)

Here are my tests first (which I did a year or two ago), giving a
basic description of the platform and the compiler options used. After
will be the code which I ran. Note that I did some marginal care to
make sure I wasn't seeing caching or preloading, but I don't claim
that these numbers are fullproof or otherwise reliable beyond a very
basic eyeball level. Specifically, I wouldn't use these numbers too
much beyond to answer "Does exception presence without ever throwing
cause overhead in C++ on X implementation?"

Note that I ran each test with input numbers to get a wallclock time
of ~30 seconds. Note that the test suite runs the tests in a (pseudo-)
random order to avoid some weird caching or optimization effects I was
seeing. (I think). Note that I do a single run of the individual test
before starting timing to try and minimize artificial caches misses.
Again, I do not claim that these tests are very thorough or robust or
even correct. I think they are.

Note that the compilers I'm using are somewhat old as well. I'm merely
using what my company used to compile our product on these platforms
several years ago. I do hope I used the right compiler options. (I did
some quick google research to determine the command line options.)

The x### is the factor comparing the slower of the two tests "virtual
exception" or "virtual fake try block" vs the test "virtual return
code".

Windows XP Pro 32
using visual studios 2003 32-bit compiler, standard release compiler
options.
Exception using code x1.04

AIX 32
% uname -a
AIX bigpine 2 5 0003DFC3D600
% xlC_r -V
C for AIX Compiler, Version 6
[Rest omitted]
% xlC_r -O4 -qnotempinc foo.cpp
Exception using code x0.94
(Yes. I have no clue why it's smaller, but it was a reproducible
number.)

AIX 64
% uname -a
AIX waco 2 5 00CAEAEA4C00
% xlC_r -V
C for AIX Compiler, Version 6
[Rest omitted]
% xlC_r -O4 -qnotempinc -q64 foo.cpp
Exception using code x1.48

HP 32
[9] % uname -a
HP-UX nimbus B.11.11 U 9000/800 2328359749 unlimited-user license
[10] % aCC -V
aCC: HP ANSI C++ B3910B A.03.73
[11] % aCC -AA -mt -z -ext -Wc,-ansi_for_scope,on +O3 foo.cpp
Exception using code x1.16

HP 64
[9] % uname -a
HP-UX cygnus B.11.11 U 9000/800 2328359751 unlimited-user license
[10] % aCC -V
aCC: HP ANSI C++ B3910B A.03.73
[11] % aCC -AA -mt -z -ext -Wc,-ansi_for_scope,on +O3 +DD64 foo.cpp
Exception using code x1.46

hp ipf
[11] % uname -a
HP-UX texan B.11.23 U ia64 0622264057 unlimited-user license
[12] % aCC -V
aCC: HP aC++/ANSI C B3910B A.06.05 [Jul 25 2005]
[13] % aCC -AA -mt -z -ext -Wc,-ansi_for_scope,on +O3 +DD64
+DSitanium2 foo.cpp
Exception using code x1.27

lin 32
[jmaurice@davey ~/test]$ uname -a
Linux davey.informatica.com 2.6.9-5.ELsmp #1 SMP Wed Jan 5 19:30:39
EST 2005 i686 i686 i386 GNU/Linux
[jmaurice@davey ~/test]$ g++ --version
g++ (GCC) 3.4.3 20050227 (Red Hat 3.4.3-22.1)
[Rest omitted]
[jmaurice@nagara ~/test]$ g++ -O3 foo.cpp
Exception using code x1.0

lin 64
[jmaurice@nagara ~/test]$ uname -a
Linux nagara 2.6.9-11.ELsmp #1 SMP Fri May 20 18:25:30 EDT 2005 x86_64
x86_64 x86_64 GNU/Linux
[jmaurice@nagara ~/test]$ g++ --version
g++ (GCC) 3.4.3 20050227 (Red Hat 3.4.3-22.1)
[Rest omitted]
[jmaurice@nagara ~/test]$ g++ -O3 foo.cpp
Exception using code x1.0

lin IA 46
[jmaurice@seraph ~/test]$ g++ --version
g++ (GCC) 3.3.1
[Rest omitted]
[jmaurice@seraph ~/test]$ g++ -O3 foo.cpp
Exception using code x1.0

sun 64
[test] uname -a
SunOS mosquito 5.8 Generic_108528-29 sun4u sparc SUNW,Sun-Fire-V440
[test] CC -V
CC: Sun C++ 5.5 2003/03/12
[test] CC -O4 +w +w2 -mt -features=extensions -xarch=generic64 -
xtarget=generic64 foo.cpp
Exception using code x1.0

sun x86
[test] uname -a
SunOS coyote 5.10 Generic_Patch_118844-30 i86pc i386 i86pc
[test] CC -V
CC: Sun C++ 5.8 2005/10/13
[test] CC -O4 +w +w2 -mt -features=extensions foo.cpp
Exception using code x1.05

////
//Start test

#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>

using namespace std;


enum ReturnCodeT { Success = 1, Failure = 2 };

class TestInterface
{
public:
virtual void virtualCanThrow(int a, int b, int targetSum) = 0;

virtual ReturnCodeT virtualReturnCode(int a, int b, int targetSum)
= 0;

ReturnCodeT inlineableReturnCode(int a, int b, int targetSum)
{ if (a + b == targetSum)
return Failure;
return Success;
}
};

inline ReturnCodeT globalInlineableReturnCode(int a, int b, int
targetSum)
{ if (a + b == targetSum)
return Failure;
return Success;
}


class TestImpl : public TestInterface
{
public:
virtual void virtualCanThrow(int a, int b, int targetSum)
{ if (a + b == targetSum)
throw 1;
}
virtual ReturnCodeT virtualReturnCode(int a, int b, int targetSum)
{ if (a + b == targetSum)
return Failure;
return Success;
}
};

class TestImpl2 : public TestInterface
{
public:
virtual void virtualCanThrow(int a, int b, int targetSum)
{ cout << "XXX" << endl;
}
virtual ReturnCodeT virtualReturnCode(int a, int b, int targetSum)
{ cout << "XXX" << endl;
return Success;
}
};


void testInlineableMemberReturnCode(TestInterface *& x, int arg1, int
arg2)
{ { vector<int> vec;
for (int i=0; i<arg1; ++i)
{ for (int j=0; j<arg1; ++j)
{ //vec.push_back(i+j);
if (Failure == x->inlineableReturnCode(i, j, arg2+3))
{ cout << "inlineable member return code, returned
failure" << endl;
x = new TestImpl2();
}
}
}
if (vec.size() && vec.back() == arg2+3)
{ cout << "inlineable member return code, vector size
comparison true" << endl;
x = new TestImpl2();
}
}
}
void testInlineableGlobalReturnCode(TestInterface *& x, int arg1, int
arg2)
{ { vector<int> vec;
for (int i=0; i<arg1; ++i)
for (int j=0; j<arg1; ++j)
{ //vec.push_back(i+j);
if (Failure == globalInlineableReturnCode(i, j,
arg2+4))
cout << "inlineable global return code, returned
failure" << endl;
}
if (vec.size() && vec.back() == arg2+4)
cout << "inlineable global return code, vector size
comparison true" << endl;
}
}
void testVirtualReturnCodeFakeTry(TestInterface *& x, int arg1, int
arg2)
{ { vector<int> vec;
for (int i=0; i<arg1; ++i)
{ for (int j=0; j<arg1; ++j)
{ //vec.push_back(i+j);
try
{ if (Failure == x->virtualReturnCode(i, j, arg2+5))
{ cout << "virtual return code with fake try,
returned failure" << endl;
x = new TestImpl2();
}
} catch (...)
{ cout << "ERROR impossible exception caught" <<
endl;
x = new TestImpl2();
}
}
}
if (vec.size() && vec.back() == arg2+5)
{ cout << "virtual return code with fake try, vector size
comparison true" << endl;
x = new TestImpl2();
}
}
}
void testVirtualReturnCode(TestInterface *& x, int arg1, int arg2)
{ { vector<int> vec;
for (int i=0; i<arg1; ++i)
{ for (int j=0; j<arg1; ++j)
{ //vec.push_back(i+j);
if (Failure == x->virtualReturnCode(i, j, arg2+6))
{ cout << "virtual return code, returned failure" <<
endl;
x = new TestImpl2();
}
}
}
if (vec.size() && vec.back() == arg2+6)
{ cout << "virtual return code, vector size comparison true"
<< endl;
x = new TestImpl2();
}
}
}
void testVirtualException(TestInterface *& x, int arg1, int arg2)
{ { vector<int> vec;
for (int i=0; i<arg1; ++i)
{ for (int j=0; j<arg1; ++j)
{ //vec.push_back(i+j);
try
{ x->virtualCanThrow(i, j, arg2+7);
} catch (int & )
{ cout << "virtual exception, exception caught" <<
endl;
x = new TestImpl2();
}
}
}
if (vec.size() && vec.back() == arg2+7)
{ cout << "virtual exception, vector size comparison true"
<< endl;
x = new TestImpl2();
}
}
}
void testManuallyInlinedReturnCode(TestInterface *& x, int arg1, int
arg2)
{ { vector<int> vec;
for (int i=0; i<arg1; ++i)
{ for (int j=0; j<arg1; ++j)
{ //vec.push_back(i+j);
ReturnCodeT retVal;
if (i + j == arg2+8)
retVal = Failure;
else
retVal = Success;
if (retVal == Failure)
{ cout << "manually inlined return code, failure
'returned'" << endl;
x = new TestImpl2();
}
}
}
if (vec.size() && vec.back() == arg2+8)
{ cout << "manually inlined return code, vector size
comparison true" << endl;
x = new TestImpl2();
}
}
}
void testManuallyInlinedOptimizedReturnCode(TestInterface *& x, int
arg1, int arg2)
{ { vector<int> vec;
for (int i=0; i<arg1; ++i)
for (int j=0; j<arg1; ++j)
{ //vec.push_back(i+j);
if (i + j == arg2+9)
{ cout << "manually inlined and optimized return
code, failure 'returned'" << endl;
x = new TestImpl2();
}
}
if (vec.size() && vec.back() == arg2+9)
{ cout << "manually inlined and optimized return code,
vector size comparison true" << endl;
x = new TestImpl2();
}
}
}

int main(int argc, char ** argv)
{
if (argc != 3 && argc != 4)
return 1;

int arg1;
if (! (stringstream(argv[1]) >> arg1))
return 1;

int arg2;
if (! (stringstream(argv[2]) >> arg2))
return 1;

TestInterface * x;

if (argc == 3)
x = new TestImpl();
else
x = new TestImpl2();

vector<clock_t> retVal;

typedef void (*TestFuncType)(TestInterface *&, int, int);
vector<pair<string, TestFuncType> > remainingTests;

remainingTests.push_back(make_pair(string("Inlineable Member
Return Code"), & testInlineableMemberReturnCode));
remainingTests.push_back(make_pair(string("Inlineable Global
Return Code"), & testInlineableGlobalReturnCode));
remainingTests.push_back(make_pair(string("Virtual Return Code
Fake Try"), & testVirtualReturnCodeFakeTry));
remainingTests.push_back(make_pair(string("Virtual Return
Code"), & testVirtualReturnCode));
remainingTests.push_back(make_pair(string("Virtual
Exception"), & testVirtualException));
remainingTests.push_back(make_pair(string("Manually Inlined Return
Code"), & testManuallyInlinedReturnCode));
remainingTests.push_back(make_pair(string("Manually Inlined
Optimized Return Code"), & testManuallyInlinedOptimizedReturnCode));

srand(time(0));

while (remainingTests.size())
{
int index = rand() % remainingTests.size();
pair<string, TestFuncType> thisTest = remainingTests[index];
remainingTests.erase(remainingTests.begin() + index);

clock_t t0 = clock();
(*thisTest.second)(x, 1, -10);
clock_t t1 = clock();
(*thisTest.second)(x, arg1, arg2);
clock_t t2 = clock();

cout << setw(40) << thisTest.first << " : " << double(t2 -
t1) / double(CLOCKS_PER_SEC) << endl;
}
}
 
J

Joshua Maurice

like environments available for me to test on, including Solaris, AIX,
HPUX, Linux, and for the common windows platforms, win32, win64,
exceptions add overhead even when not thrown, some worse than others.

That should read "I have done tests on X platforms, and of those X,
roughly half implement exceptions the slow aka bad aka not table way",
not "The listed platforms are all bad." Some of the listed platforms
implement exceptions the good way. See earlier posts. Sorry for the
confusion.
 
J

Joshua Maurice

lin IA 46
[jmaurice@seraph ~/test]$ g++ --version
g++ (GCC) 3.3.1
[Rest omitted]
[jmaurice@seraph ~/test]$ g++ -O3 foo.cpp
Exception using code x1.0

Ack again. I just copied and pasted something I had lying around, and
apparently it was in error. That's supposed to be "lin IA 64", and I
missed the "uname -a" results.

[jmaurice@seraph ~]$ uname -a
Linux seraph 2.6.9-34.EL #1 SMP Fri Feb 24 16:49:08 EST 2006 ia64 ia64
ia64 GNU/Linux

Sorry. It's late for me, and I wanted to be prompt with my reply for
the curious Ian Collins.
 
B

Bo Persson

Joshua said:
Sadly no. That was the intent. However, on half of all of the unix-
like environments available for me to test on, including Solaris,
AIX, HPUX, Linux, and for the common windows platforms, win32,
win64, exceptions add overhead even when not thrown, some worse
than others. Windows, for example, implements C++ exceptions on top
of their structured exception handling, which means that you're
paying a penalty every time you enter a try block.

That's true for win32, but not for win64.
Not that I'm trying to say use exceptions or don't in this post.
Just understand their practical costs and don't repeat (wishful)
misinformation.

Right! :)


Bo Persson
 
T

Thomas J. Gritzan

Joshua said:
That should read "I have done tests on X platforms, and of those X,
roughly half implement exceptions the slow aka bad aka not table way",
not "The listed platforms are all bad." Some of the listed platforms
implement exceptions the good way. See earlier posts. Sorry for the
confusion.

You only have Win32 in your list, but not Win64 on either IA64 nor AMD64.

Do you have numbers for those, too?
 
J

Joshua Maurice

You only have Win32 in your list, but not Win64 on either IA64 nor AMD64.

Do you have numbers for those, too?

Not offhand. I could run tests for them potentially when I get some
spare time. I have been told or read that the win64 platform has a
different ABI which handles exceptions different, the correct way,
unlike win32. I know nothing of win IA 64 or win AMD 64. .
 
W

White Wolf

Joshua said:
Sadly no. That was the intent. However, on half of all of the unix-
like environments available for me to test on, including Solaris, AIX,
HPUX, Linux, and for the common windows platforms, win32, win64,
exceptions add overhead even when not thrown, some worse than others.
Windows, for example, implements C++ exceptions on top of their
structured exception handling, which means that you're paying a
penalty every time you enter a try block. For a particularly contrived
test I once wrote, I got performance slowdowns of up to ~1.5x slower
than the version which used error return codes on one platform.

Not that I'm trying to say use exceptions or don't in this post. Just
understand their practical costs and don't repeat (wishful)
misinformation.

My tests on Linux, Windows and Solaris has shown different results than
yours.
 
T

Thomas J. Gritzan

Joshua said:
Not offhand. I could run tests for them potentially when I get some
spare time. I have been told or read that the win64 platform has a
different ABI which handles exceptions different, the correct way,
unlike win32.

I also read that the ABI changed to table-based exceptions in Windows
for AMD64. I guess they won't change it for Win32, as it would break
some code (or binary compatibility on library interfaces); and it
doesn't matter to them because too few customers use exceptions.
I know nothing of win IA 64 or win AMD 64. .

You list lin 32, lin 64 and lin IA64, where uname says:
1) i386
2) x86_64
3) ia64

No. 1 is the known Intel x86 compatible desktop architecture.
No. 2 is the 64-bit extension of it developed by AMD and licensed by
Intel (sometimes called AMD64).
No. 3 is the 64-bit server architecture also known as Itanium.
Windows also runs on all three, and each is another platform on its own
with a different ABI. So it's ambiguous to say Win64, or "the 64-bit
Windows platform", as there are two.
 
J

Joshua Maurice

My tests on Linux, Windows and Solaris has shown different results than
yours.

I'm curious as to your test code and testing methods, exact numbers,
uname -a, OS version, compiler version, and compiler (and linker)
options. What are your results?
 
J

Joshua Maurice

Joshua Maurice schrieb:





I also read that the ABI changed to table-based exceptions in Windows
for AMD64. I guess they won't change it for Win32, as it would break
some code (or binary compatibility on library interfaces); and it
doesn't matter to them because too few customers use exceptions.


You list lin 32, lin 64 and lin IA64, where uname says:
1) i386
2) x86_64
3) ia64

No. 1 is the known Intel x86 compatible desktop architecture.
No. 2 is the 64-bit extension of it developed by AMD and licensed by
Intel (sometimes called AMD64).
No. 3 is the 64-bit server architecture also known as Itanium.
Windows also runs on all three, and each is another platform on its own
with a different ABI. So it's ambiguous to say Win64, or "the 64-bit
Windows platform", as there are two.

Good to know. Thank you. I probably would have discovered this when I
looked up proper compiler options and such, but I did not know before
this.
 
T

Thomas J. Gritzan

Andy said:
I suppose Dec Alpha 64-bit Windows is dead enough to ignore... and MIPS
is even more obscure?

http://en.wikipedia.org/wiki/Windows_NT
"Windows NT 4.0 was the last major release to support Alpha, MIPS, or
PowerPC, though development of Windows 2000 for Alpha continued until
August 1999"

The current Windows DDK (driver development kit) supports only x86, x64
and IA64 (for Windows Server 2003 and Longhorn).
 
D

dragan

peter said:
I was referring to the std::string that was the result of the
computation.

Again, it wasn't an example of production code but rather a hint at a whole
ream of stuff available in the area of C/C++ error "handling".
You are assuming that you can only have one kind of error?

ERROR "expands" to a specific error. (Surely I wasn't that lame?).
In real
life more than one thing can go wrong,

Don't play games with me if you are, cuz you know I am sensitive to such
childisness and will jump all over you for it for YOU will be the one who
"drew first blood".
the reason being kept in the
return code. That is why you use an int, not a bool.

I used an int! (didn't I?). Unsigned even, no doubt, to suggest yet another
partitioned and available semantic from nothing more than a number.
You are welcome to use your own class if that would simplify things.

Aside (don't reply to this because it is rhetorical): How could it NOT be
more simpler?! The C++ string brings in every compiler "feature" known to
man!
You forgot to comment about this point.

It wasn't, again, intended as production code. It was for those thinking and
believing that nothing but C++ exceptions exist as a solution to errors. Of
course, and ironically, the C++ mechanism is derived directly from C's
setjmp/longjmp. Whereas programmers once used to evaluate and choose between
alternative mechanisms, C++ not only recommends ONE, but "dumbs-down"
programmers (read: makes for dangerous programmers, not makes for cheap
project labor. Think about it).
 
D

dragan

James said:
James said:
James Kanze wrote:
James Kanze wrote:
"dragan" ha scritto nel
[....]
That's the whole point of exceptions. They're for the
sort of problems where it doesn't matter where the
problem occured; the handling is the same. If you run
out of memory processing a request, for example, it
doesn't matter where you were in the processing when you
ran out; you just abort the request (but not the
process) with an error message, and continue.
You seem to be big on aborting.
Attention about word use. There's aborting (in the sense
of calling abort()), and aborting (in the more general
sense, of immediately terminating some action that you
were in the process of doing). In this case, I'm using
the other sense: say you've received a request on your
LDAP server, and you run out of memory trying to service
it (because it requires interpreting some obscenely
complicated filter expression, for example). When you
detect the lack of memory, you're down in some really deap
parsing function, executing operator new. You (or rather
the system) raises an std::bad_alloc exception, which you
catch at the top level, and abort the request (not the
program), returning an error message of "insufficient
resources", or the like.
Ah. Bad choice of word then to describe that.
I didn't invent the language (English). I just use it.
Don't worry about. It's my "second language", but maybe that
elicited me to study it more. I have found no error in you use
of English.
It sounds like an "unstudied appropriation". "Hurried".
Inappropriate and incorrect.

It is the standard word for this.

Then hopefully I have corrected the widespread incorrectness.
The C function takes its name
from everyday usage: to abort an action is to terminate it
bruskly.

Oh, you meant "abort". I thought you were talking about "error management"
vs. "error handling" vs. "error propogation". But on your noted usage
though: I find it like I said before. To me, "abort" without other context
means exit().
In transaction terminology, it's frequent to speak of
aborting a transaction (which results in a roll-back instead of
a commit); in server technology, it's frequent to speak of
aborting a request. And so on. The C function aborts the
process, but processes are far from the only things which can be
aborted.

I'm "all over that" .. nevermind! It's not important. You were wrong yet
again: I have to move on.
Sorry, but in this context, "abort" is the standard word,

Oh, and I'm all about being taxed by the standard. Pfft. Nuff said. As if
you didn't know anything and are picking nits.
and
has been pretty much everywhere I've worked. It's also been the
word I've seen used in literature.

It's not important. It is your "personal process" (ref to Watts Humphrey
maybe). Step "one": unlearn programmers' personal ideas and educate them in
the required definitions. (Note that C++ projects are like herding cats..
umm, still?).
You're the first person who's accused me of that:). I'm
usually accused of being too sure of myself.

Rhetorically, I was just wondering (and I DO NOT wanna know!)... nevermind,
I already know.
[...]
I could call you facetious, but I think you trully are not
following the main points. Your scapegoat is that you follow
too many threads. I said "preallocate", but just like I said
that error handling (not "management" this time) is
application-specific, so is that one specific error.

Yes, but I presented a very specific case: parsing an LDAP
request.

I don't know or care how you ATTEMPTED to CHANGE the context. It's not my
current focus.
An LDAP request can be arbitrarily complex, and can
require an arbitrarily large amount of memory. How do you
"pre-allocate" an arbitrary large amount of memory? No matter
how much you pre-allocate, it might not be enough.

I don't really think that I can't build that program, do you? :p I have
work to do, and it isn't helping you solve YOUR problems.
[...]
You don't really expect me graft my discussion on your
post-conceived scenario, do you? That would be so
"unsporting".

In other words, you prefer to ignore issues that you don't
understand.

I suggest that you are trying to milk me for free info. IOW, I not buyin'
your spiel for a second. Apparently you are on the path of knowing
everything about nothing. You're welcome.
 
P

peter koch

Again, it wasn't an example of production code but rather a hint at a whole
ream of stuff available in the area of C/C++ error "handling".





ERROR "expands" to a specific error. (Surely I wasn't that lame?).


Don't play games with me if you are, cuz you know I am sensitive to such
childisness and will jump all over you for it for YOU will be the one who
"drew first blood".


I used an int! (didn't I?).  Unsigned even, no doubt, to suggest yet another
partitioned and available semantic from nothing more than a number.

Yes - it was int in your code, but with only two values - OK and ERROR
- that effectively makes it boolean. The point was that your macroes
can't keep the return values from the called function.

Now, this part of the thread was about readability of code using
exceptions versus code using some other scheme. I gave an example of
what real life code not using exceptions looks like and demonstrated
how error-handling takes up a big part of the code and obscures the
algorithm. My example had a one-liner using exceptions translate into
a 10-liner using return-codes.
You then condensed it - using some macroes to six lines of code; but
not doing as much as the original code and thus not being a fair
comparison.

[snip]
It wasn't, again, intended as production code. It was for those thinking and
believing that nothing but C++ exceptions exist as a solution to errors.

Noone in this thread claims that. The consensus seems to be to return
error-codes if the fault will be handled locally and throw an
exception otherwise.
Of
course, and ironically, the C++ mechanism is derived directly from C's
setjmp/longjmp. Whereas programmers once used to evaluate and choose between
alternative mechanisms, C++ not only recommends ONE, but "dumbs-down"
programmers (read: makes for dangerous programmers, not makes for cheap
project labor. Think about it).

No. longjmp/setjmp is not related to exceptions. Do not use longjmp/
setjmp in your C++ code ever: it will likely not work.

C++ recommends return-codes, storing the error in some (thread)static
variable or exceptions. All three strategies are present in the
standard library.
Naturally - and sensibly - the standard method is throwing an
exception. This is good and correct: almost all library code should
throw as a default - perhaps augmented (as is std::new) with a nothrow
option.

/Peter
 
D

dragan

peter said:
No. longjmp/setjmp is not related to exceptions.

Yes, it is. It was an "advanced" EH technique in C and exceptions model that
basic behavior. That's why C++ exceptions are "derived" from that technique.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,792
Messages
2,569,639
Members
45,353
Latest member
RogerDoger

Latest Threads

Top