Article on possible improvements to C++

W

White Wolf

sfuerst said:
Hello, I've written an article at http://locklessinc.com/articles/10_problems_with_c++/ [SNIP]
Any comments, or flames are welcome. :)

Your captcha at the web does not work, so I have to put here my comment:

I may sound critical, but it is just my inability to talk properly. I
can understand why you wanted to share your thoughts and I understand
that you have placed a great deal of concern and work into this article.
However, it is full of bull byproduct. ;) It shows clearly that there
is a lot you don't know about C++. You have serious misunderstandings.
I don't know if the blame falls on bad teachers or bad books, or what,
but your misconceptions and misunderstandings run deep and seem to be
fundamental. They remind of some colleagues from a decade ago, who have
learnt C++ from a Java guy; so all they knew about C++ were
misconceptions and a fundamental hate and distrust towards the language. :)

Fixing your language knowledge issue is simple. Get a good book. I
suggest Bjarne's new book.

But there is another problem. And that is an attitude problem. You
make wild assumptions and then you act on them as if they were true,
without checking their validity. That is a very dangerous, I would say
suicidal way of working for a programmer. I have seen one software that
was 2 times slower because the head architect assumed that dynamic
memory allocation is expensive and he has forced people to statically
allocate all memory. He did not check his assumptions. And they were
wrong.

So my suggestion to you is to be aware of your assumptions and check
them before you act on them. I have only looked at the first 3 points,
because I saw a pattern and frankly I have decided that if the quality
of your arguments is the same as in the first 3 point, I don't want to
frustrate myself with reading the rest. But even in those first 3
points you will see the examples where you have had a wrong assumption
and instead of checking if the assumption is correct, or asking for
advice on USENET about your way of thinking, you have acted upon your
assumptions. Why is that bad? Well, for one, posting the link to this
article on the USENET triggered two things:

1.) Experienced people are frustrated, concerned or laugh about your
article. Some, like I, may even go into damage control mode, because of
reason 2

2.) Unexperienced people won't be able to see that your assumptions are
wrong, because you state your wrong assumptions as facts. So they will
accept what you say. And that will cause them harm, because later in
life they will have to spend serious time and effort to unlearn all the
bad things they have read here.

*** The complaints in item #1 are based on 3 serious misconceptions and
some more:

1.) operator new cannot be replaced. It can. See your favorite C++
textbook.

2.) The new operator combines 2 operations: allocation and
initialization. Clearly a misconception. The new operator *only*
allocates memory. It does not combine anything else. Constructors do
the initialization.

3.) Array allocation is inefficient. It is not. It is more efficient
than any hand crafted code any of us could ever write.

Your problem seems to be here that you want to work in C++ as you would
work in C or assembler. There is no need for you to fiddle around with
allocating arrays and with placement new. Use a vector and initialize
it from a pair of input iterators. You get the most effective code
possible.


*** The complaints in item #2 are based on 2 serious misconceptions and
some more:

1.) Exceptions are means to decouple the site of error detection and
error handling. They have nothing to do with goto. They are not jumps.
They are based on sound principles that does not break or even bend
the rules of structuring programming.

2.) Exceptions have not been created because constructors cannot return
values. Serious misconception. They had to be added into the language,
because of it. But the motivation for the design and existence of
exceptions has nothing to do with constructors. It has to do with the
desire to make errors harder to hide (error codes can be ignored without
consequences); the need to make code between the detection site and the
handling site be "untouched" by the fact that an error may occur
(error/return codes have to be delegated by all functions on the call
stack); and the needs to fully separate the detecting code and the handler.

Your example with the class with the crazy error code reference argument
is as bad as it could be. If your constructor exists normally, while
not creating the object properly, you are living in
undefined-behavior-land. You have a variable with the type
Transmogrifier, but it is *not* a transmogrifier! You ignore the error
code, or you do not return from your function or exit the block where
the variable is living... anyone later may start using that object as if
it were properly constructed. The compilers won't and cannot stop you
from doing it (in any language I know). But that object is not
constructed properly, so your code will do stupid things.


*** The complaints in item #3 are based on at least one serious
misconception:

You think that compilers are dumb. That they will do 2 additions when
one suffices. They don't. That extra addition is removed at compile
time. If a compiler is requested to access an element of an object (any
element) it will use a compound access with a base register and an
offset. ALWAYS. Compilers are not stupid. The expression to access an
element in case of multiple inheritance is something like this:

address[base_adjustment+element_offset]

where both base_adjustment and element_offset are compile time
constants! So in the final binary/machine code you will see:

address[base_adjusted_element_offset]

No speed loss whatsoever.


BR, WW
 
B

Balog Pal

White Wolf said:
2.) The new operator combines 2 operations: allocation and initialization.
Clearly a misconception. The new operator *only* allocates memory. It
does not combine anything else. Constructors do the initialization.

This one is actually true. The "new operator" combines several things:

- call "operator new" (not to confuse!)
- initialize calling ctor
- call part destructors and "operator delete" in case exception escapes the
ctor call

The misconception lies in the claim it is a bad thing. :-o

new operator example:
int * pInt = new int(42);

operator new example:
void* operator new(size_t s) { /* return pointer to properly allocated
memory */ }
 
W

White Wolf

Balog said:
This one is actually true. The "new operator" combines several things:

- call "operator new" (not to confuse!)
- initialize calling ctor
- call part destructors and "operator delete" in case exception escapes
the ctor call

The misconception lies in the claim it is a bad thing. :-o

new operator example:
int * pInt = new int(42);

operator new example:
void* operator new(size_t s) { /* return pointer to properly allocated
memory */ }

I assumed he is talking about operator new, since he wanted to replace
it, and his motivating example was about about replacing malloc. And
its equivalent is not the new operator, but operator new.

So I have assumed that the guy is simply confusing things and using the
wrong terminology, as he does in the rest of his article.
 
D

dragan

White said:
2.) The new operator combines 2 operations: allocation and
initialization. Clearly a misconception. The new operator *only*
allocates memory. It does not combine anything else. Constructors do
the initialization.

Operator new allocates memory and calls a constructor. It does do 2 things.
Placement new does one thing: it calls a constructor.
1.) Exceptions are means to decouple the site of error detection and
error handling. They have nothing to do with goto. They are not
jumps. They are based on sound principles that does not break or
even bend the rules of structuring programming.

I believe he said that they can be like a goto in what they CAN turn code
into: spaghetti.
2.) Exceptions have not been created because constructors cannot
return values. Serious misconception. They had to be added into the
language, because of it. But the motivation for the design and
existence of exceptions has nothing to do with constructors. It has
to do with the desire to make errors harder to hide (error codes can
be ignored without consequences); the need to make code between the
detection site and the handling site be "untouched" by the fact that
an error may occur (error/return codes have to be delegated by all
functions on the call stack); and the needs to fully separate the
detecting code and the handler.

Why does it have to be one or the other extreme? Exceptions are just one of
many ways to handle errors. Use what is most appropriate.
 
W

White Wolf

dragan said:
Operator new allocates memory and calls a constructor. It does do 2 things.
Placement new does one thing: it calls a constructor.

Sorry, but no. The global new operator, when it is called, does the two
things you talk about. Operator new does only one thing. Sorry, no
bonus for you in knowing the terminology.
I believe he said that they can be like a goto in what they CAN turn code
into: spaghetti.

And I believe I have described clearly why there aren't at all like
goto, and instead of coupling things (which turns code into spaghetti)
exceptions decouple things (which turn code into ravioli).
Why does it have to be one or the other extreme? Exceptions are just one of
many ways to handle errors. Use what is most appropriate.

Where did I say it has to be one or the other extreme?
 
D

dragan

White said:
Sorry, but no. The global new operator, when it is called, does the
two things you talk about. Operator new does only one thing. Sorry,
no bonus for you in knowing the terminology.

No "bonus" for you playing (English) language lawyer instead of recognizing
the context in which 'new' was being discussed. :p
And I believe I have described clearly why there aren't at all like
goto, and instead of coupling things (which turns code into spaghetti)
exceptions decouple things (which turn code into ravioli).

Bad is bad, period. You seem to have agenda (a childish one).
Where did I say it has to be one or the other extreme?

I didn't say "you" specifically.
 
W

White Wolf

dragan said:
No "bonus" for you playing (English) language lawyer instead of recognizing
the context in which 'new' was being discussed. :p

I have clarified your confused use of C++ (and not English) terminology.
This was supposed to be helpful. The terms "operator new" and "the
new operator" (there is only one, conceptual thing) are not the same
thing. They have two distinct definition in C++.
Bad is bad, period. You seem to have agenda (a childish one).

Oh my. Which one is childish? Using actual arguments to prove a point
(what I did) or accusations and personal insults (what you did)?
I didn't say "you" specifically.

Nice of you. Since the post was addressed to me, I wrongly assumed that
all comments were about what I wrote, especially since it has followed a
quote of mine, talking about the same topic.
 
D

dragan

White said:
I have clarified your confused use of C++ (and not English)
terminology. This was supposed to be helpful. The terms "operator
new" and "the new operator" (there is only one, conceptual thing) are not
the same
thing. They have two distinct definition in C++.

I know that Mr. Insinuator. Get some intuitiveness already. :p
Oh my. Which one is childish? Using actual arguments to prove a
point (what I did) or accusations and personal insults (what you did)?

I don't accuse or insult. You Mr., need to introspect.
Nice of you. Since the post was addressed to me, I wrongly assumed
that all comments were about what I wrote, especially since it has
followed a quote of mine, talking about the same topic.

You seem keen on exploiting nits in attempt to create false impressions.
Children do that. That's what grown-ups know though, so it just confirms to
them that they are doing the proverbial "arguing with a child" thing. So, if
you want to stop appearing childish, grow up!

:p
 
W

White Wolf

dragan said:
No "bonus" for you playing (English) language lawyer instead of recognizing
the context in which 'new' was being discussed. :p


Bad is bad, period. You seem to have agenda (a childish one).

Just a clarification. The OP said exceptions are bad, because they are
like goto. I have provided an argument to show why exceptions are not
like goto and why they will not turn the code into spaghetti the way
goto does. So I have proven the argument that they are like goto, and
they will turn your code into a spaghetti is not true. Therefore the
original assumption that they are bad does not hold.

After that, your answer is above...

I have no idea why you think that this is some kind of pissing contest.
I come here to talk about C++ and to help people to understand it, and
to help them to discover their mistakes in thinking, or in understanding
- for their benefit. This is not about me being right or not. Most of
the time we are talking about scientific facts. Things that can be
proven. With logic. Vulcan style. Emotions suppressed.

Exceptions and and goto are nothing alike. Those attributes of goto
that make goto easy to misuse are not present with exceptions:

- goto can jump anywhere in the code as long as it does not jump over
the initialization of a variable

- goto creates a new control flow that is independent of anything
"normal" (without goto)

- goto preserves states, and it is very hard to tell where those states
come from

- therefore the code before the goto and after the goto may
"communicate" with each other in unforeseen ways

Exceptions are quite different:

- exceptions cannot go just anywhere in the code

- exceptions may abort the code (no handler) or "track back" on the same
way the code came to the throw site

- so exceptions do not create a completely new control flow, they just
automate one that would exist otherwise: the many ifs checking return
codes and returning to the caller if there is a failure

- exceptions are just an automated way of creating the control flow that
would exist anyway to handle errors

- exceptions do not preserve state, they destroy state created in all
blocks that they exit

- of course, side effects of those functions won't seize to exist unless
we take explicit actions (in destructors implementing a transactional
behavior) but we would have to make those also if we used return codes

- the only way exceptions communicate with the other end of the "jump"
is the object being thrown,and that object is like the return code we
would have to return anyway

I don't know if you can follow my reasoning, I hope I have managed to
explain what I mean.

Please believe me, I am not writing to the USENET so that I can start
arguments with people. I am writing so that I can share what I have
learnt, and hopefully provide some valuable insight for those who read.
 
W

White Wolf

Right. You have managed to produce an entire post filled only with
insult and name calling. If it makes you happy, call me childish. OTOH
I would be more interested in adult conversation. So if you happen to
find a technical inaccuracy in what I say or have said, please let me know.

As for insults, please save some bandwidth and disk space for the future
generations, and do not post them here. Let's agree: For every post I
read from you addressed to me, I will implicitly assume that you have
said that I am a childish jerk. You have repeated that assertion of
yours enough times that your message is clear. There is no need to keep
repeating.

In that way we can save a lot of typing for you, and also keep the
discussion on the technical topics. That would be the reason for this
forum anyway.
 
D

dragan

White said:
Right. You have managed to produce an entire post filled only with
insult and name calling.

I wouldn't do that. Ask anyone who knows me.
If it makes you happy, call me childish.

It'll be OK. Get some sleep.
OTOH I would be more interested in adult conversation.

You have time for that later. Enjoy your youth.
So if you happen to
find a technical inaccuracy in what I say or have said, please let me
know.

Oh ho, oh OK. I will do that. (hehehe).
As for insults, please save some bandwidth and disk space for the
future generations, and do not post them here.

Your current tactic: redirect away from the issue at hand. "Nice try".
Let's agree: For
every post I read from you addressed to me, I will implicitly assume
that you have said that I am a childish jerk.

Is my teaching helping you understand? You seem more keen on testing your
tactics than learning and accepting.
You have repeated that assertion of
yours enough times that your message is clear. There is no need to
keep repeating.

OK, quiz time to see if you have learned anything. Please write down what my
purpose is in entertaining and "exposing" your childish tactics. Also,
please go back in this thread and write down what the meaning is of every
word I enclosed in quotation marks and how the context would differ had I
not used the quotation marks (single words only, as quoted passages are
distinctly different). Use as much space as you wish and take as much time
as you need.

(OK, you don't have to write anything: just THINK about it and think about
how you are perceived by others).
In that way we can save a lot of typing for you, and also keep the
discussion on the technical topics. That would be the reason for this
forum anyway.

"the bottom line is...", is a cliche with intent to summarize that which one
cannot summarize but which one feels the need to "sum up" anyway. You
homework is to THINK!
 
D

dragan

White said:
Just a clarification. The OP said exceptions are bad, because they
are like goto. I have provided an argument to show why exceptions
are not like goto and why they will not turn the code into spaghetti
the way goto does. So I have proven the argument that they are like
goto, and they will turn your code into a spaghetti is not true. Therefore
the original assumption that they are bad does not hold.

After that, your answer is above...

I have no idea why you think that this is some kind of pissing
contest. I come here to talk about C++ and to help people to
understand it, and to help them to discover their mistakes in
thinking, or in understanding - for their benefit. This is not about
me being right or not. Most of the time we are talking about
scientific facts. Things that can be proven. With logic. Vulcan
style. Emotions suppressed.
Exceptions and and goto are nothing alike. Those attributes of goto
that make goto easy to misuse are not present with exceptions:

- goto can jump anywhere in the code as long as it does not jump over
the initialization of a variable

- goto creates a new control flow that is independent of anything
"normal" (without goto)

- goto preserves states, and it is very hard to tell where those
states come from

- therefore the code before the goto and after the goto may
"communicate" with each other in unforeseen ways

Exceptions are quite different:

- exceptions cannot go just anywhere in the code

- exceptions may abort the code (no handler) or "track back" on the
same way the code came to the throw site

- so exceptions do not create a completely new control flow, they just
automate one that would exist otherwise: the many ifs checking return
codes and returning to the caller if there is a failure

- exceptions are just an automated way of creating the control flow
that would exist anyway to handle errors

- exceptions do not preserve state, they destroy state created in all
blocks that they exit

- of course, side effects of those functions won't seize to exist
unless we take explicit actions (in destructors implementing a
transactional behavior) but we would have to make those also if we
used return codes
- the only way exceptions communicate with the other end of the "jump"
is the object being thrown,and that object is like the return code we
would have to return anyway

I don't know if you can follow my reasoning, I hope I have managed to
explain what I mean.

Please believe me, I am not writing to the USENET so that I can start
arguments with people. I am writing so that I can share what I have
learnt, and hopefully provide some valuable insight for those who
read.

Oh brother. At this rate, you'll be reposting the entire Wikipedia in short
order.
 
W

White Wolf

You have again managed to produce an entire post filled only with insult
and name calling. The rest you know.
 
D

dragan

White said:
You have again managed to produce an entire post filled only with
insult and name calling. The rest you know.

Avoiding the issue will not help you. And no amount of "smoke and mirrors"
tactics can change the past. Save the posts for a time when you are more
secure if reality is too much for you right now. I assure you that you will
chuckle then. :)
 
S

stan

Pavel said:
sfuerst wrote:
Maybe if C had a good preprocessor there would be no need for those ugly
templates in C++. And then an average-sized program would not take
infinity to compile at multi-GHz CPU. And you wouldn't get 9999
9997-character lines of unreadable error messages for missing a const
keyword or forgetting to include a header file with yet another overload
of << operator. All pipe dreams I guess..

I remember how Turbo-C and especially Turbo-Pascal used to compile on
5-MHz CPU and can't help crying :)

How's that for a good flame igniter?

As for flames, I'm pretty sure I saw Turbo Pascal actually cause at
least two machines burst into flames it was so fast.

I remember it took me two days to be convinced it wasn't a joke and it
really was that fast. At the time we were timesharing several machines
but mostly an HP mini and until TP I actually thought the HP wasn't
too bad.
 
A

Alf P. Steinbach

* White Wolf:
Sorry, but no. The global new operator, when it is called, does the two
things you talk about. Operator new does only one thing. Sorry, no
bonus for you in knowing the terminology.

He he, I see a little flame war erupted over that. :)

A good way to talk about this is IMO "new expression" versus "operator new" or
"new operator". The operator is an allocation function only (whether it's per
class or global). The expression, involving the new keyword, calls the
allocation function with the supplied allocation function arguments, and then,
if that succeeds, calls the constructor with the supplied constructor arguments.

"Placement new" was probably originally referring to the ability to specify some
existing storage, a placement of the object, but in the standard's terminology
"placement" refers to any allocation function with extra arguments, or new
expression supplying such arguments.

Technically a placement new expression does the same as a non-placement new
expression.

Also, there's no big difference for a global new operator.


Cheers,

- Alf
 
P

Pavel

dragan said:
Quite easily actually. An example is the new operator's set_new_handler.
It's of no use if the client code wants to know about the failure in few
higher-level callers. Of course you can create a class for every
overloaded + operator that can overflow, create a method "onOverflow()"
in it etc. but what level of cooperation would it require from the
client code to add and remove interested parties?

And what will be the cost of these additions/removals?

And what would be the cost of dispatching different errors if all are to
be processed after the same code point (something that you achieve with
several catch blocks when using the exception)?

And what will it cost you to program stopping normal flow, destroying
automatic objects and actually arriving to the desired error-processing
point in code?

Long story short, for a significant share of tasks set_new_handler
approach is certainly not a solution, not even good enough for operator
new itself (that's why std::bad_alloc was added).

-Pavel
 
D

dragan

Pavel said:
It's of no use if the client code wants to know about the failure in
few higher-level callers.

OK, I mis-comprehended your thought, probably because you used "10" instead
of "3".
Of course you can create a class for every
overloaded + operator that can overflow, create a method
"onOverflow()" in it etc. but what level of cooperation would it
require from the client code to add and remove interested parties?

I don't have the data/information across a wide variety of software to
assess how important that is, BUT, I feel it's probably "a detail".
"Operator overloading is for numerics", to say a cliche.
And what will be the cost of these additions/removals?

And what would be the cost of dispatching different errors if all are
to be processed after the same code point (something that you achieve
with several catch blocks when using the exception)?

Error handling code is usually not performance-critical, so it doesn't
matter.
And what will it cost you to program stopping normal flow, destroying
automatic objects and actually arriving to the desired
error-processing point in code?

Performance-wise? Who cares? Mechanics-wise? A little bit of code that may
indeed help to focus on doing error handling rather than dispatching errors.
Long story short, for a significant share of tasks set_new_handler
approach is certainly not a solution, not even good enough for
operator new itself (that's why std::bad_alloc was added).

If by "solution" you mean "one size fits all", there is no answer. Not
without concession anyway.
If you like exceptions, use them. I prefer to avoid them when/wherever
possible. I don't do large-scale development and I have a toolbox full of
error-handling techniques. I never understood this quest for "one and only
one" when that is hardly ever appropriate: one error-management mechanism,
one "standard" library, one <your choice here>...


Locally handle-able conditions (errors) are much more numerous than global
errors handle-able appropriately by a technique such as set_new_handler.
There has to be a number of approaches to error handling or else it is a
lame solution to the problem of error management, so I say. C++ exceptions
can replace those set_new_handler-like things. Sure, you can use them at the
local level too, but then with that comes all the confusion of when to just
crutch on the mechanics or think about the problem and handle the error, and
it's the whole "exceptional case botching up the common case" thing again.
The real sad thing about C++ exceptions is that it suppresses thought about
error handling in general and the science of error handling almost
stagnates, in C++ groups anyway.
 
D

dragan

Alf said:
* White Wolf:

He he, I see a little flame war erupted over that. :)

No it didn't. He was trying to exploit colloquial usage of "new operator"
even though it was very clear what was being discussed. I called him out on
his childish tactics and agenda. It was a general discussion about
allocation, inititalization and construction (or was about to be) until the
child saw an avenue to exploit.
A good way to talk about this is IMO "new expression" versus
"operator new" or "new operator".

It was immaterial, for in the context, it was clear what was being
discussed.
"Placement new"

is manually calling a constructor. It is "CONSTRUCTION" (a bad choice of
terminology, but so it is in C++).
 

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

Members online

No members online now.

Forum statistics

Threads
473,766
Messages
2,569,569
Members
45,042
Latest member
icassiem

Latest Threads

Top