Article on possible improvements to C++

S

sfuerst

Hello, I've written an article at http://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.
The list kind of looks like the typical one brought up by novices,
complaining about things like exceptions and multiple inheritance.
However, the actual issues discussed tend to be more subtle and low-
level than what you are probably thinking. In particular, none of the
"problems" are complaints about the existence of features, just on
their current syntax, or typical underlying implementation.

The 10 problems are:
1) The "new" keyword.
2) Exceptions
3) Implementations of Multiple Inheritance
4) Member Pointers and Member Function Pointers
5) 0 is NULL
6) Operator Overloading
7) Template Syntax
8) The "export" Keyword
9) Classes verses Structs
10) Barriers

Unfortunately, some of the solutions aren't particularly good. (The
worst one probably is a replacement syntax for the new keyword.)
However, constructive criticism has to start somewhere.

Any comments, or flames are welcome. :)

Steven
 
A

Alf P. Steinbach

* sfuerst:
Hello, I've written an article at http://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.
The list kind of looks like the typical one brought up by novices,

He he, it certainly does. :)

But kudos (speling?) to you for writing it up.

For that can both help you and help many others.

complaining about things like exceptions and multiple inheritance.
However, the actual issues discussed tend to be more subtle and low-
level than what you are probably thinking. In particular, none of the
"problems" are complaints about the existence of features, just on
their current syntax, or typical underlying implementation.

The 10 problems are:
1) The "new" keyword.

OK, there's much wrong.

First, "Unfortunately, the new keyword doesn't allow [...] an override." is
wrong. You override the allocation aspect by defining operator new (and/or
operator new[], which is the allocation function, which can be overridden per
class as well as overriding the global default (where, to boot, you can override
the action taken on allocation failure via set_new_handler). And you can
"override" the initialization action by defining suitable constructors.

Second, this is wrong: "A second problem with the new keyword is that it
combines two different operations in one. The first is to allocate memory, the
second is to initialize it. This combination means that initializing an array is
impossible to do with anything other than the default constructor."

'new' is designed to very strongly couple allocation and initialization, with
automatic rollback. It's extremely tricky to do manually, that is, to do it
correctly without language support. If C++ didn't have 'new' to do it, it would
need some other mechanism to do it, which would then be used instead of 'new'.

Also, it's wrong that it's impossible to initialize an array in other ways than
using a default constructor.

For example,

std::vector<int> a( 42, 999 );

Third, this is wrong: "Similarly, destructing an array with the delete[]
operator is inefficient.". delete[] is designed for maximal efficiency. The
trade-offs made to achieve that efficiency, in particular that the programmer
must supply the knowledge of whether it's delete or delete[] (just in order to
save a byte or two of memory!) is a problem, but the efficiency is not. :)

Now, to your (rhetorical) question, "If all backwards compatibility were thrown
out, how could construction, initialization, and memory allocation be better
done, (paying particular attention to orthogonality)?"

This is addressed in C++0x, which unfortunately seems to be a long way from
ratification, but still.

It's an initialization syntax based on curly parentheses initializers.

2) Exceptions
3) Implementations of Multiple Inheritance
4) Member Pointers and Member Function Pointers
5) 0 is NULL
6) Operator Overloading
7) Template Syntax
8) The "export" Keyword
9) Classes verses Structs
10) Barriers

Unfortunately, some of the solutions aren't particularly good. (The
worst one probably is a replacement syntax for the new keyword.)
However, constructive criticism has to start somewhere.

Any comments, or flames are welcome. :)

I skimmed the section on Exceptions, it is also full of misconceptions. But
those are more arguable, questions more of design than how things work
technically. However, others will probably chime in for the rest (also about
what's wrong with section 2), and I hope my comments on section 1 help.


Cheers,

- Alf
 
M

maverik

* sfuerst:
This combination means that initializing an array is
impossible to do with anything other than the default constructor."
[skip]

Also, it's wrong that it's impossible to initialize an array in other ways than
using a default constructor.

For example,

     std::vector<int> a( 42, 999 );

I think, he means that 'new' uses default constructor and there is no
way (AFAIK) to use parameterized constructor with 'new'. Something
like this

int *p = new int[3] { 1, 2, 3};

Of course, I don't know why this may need
 
P

Pavel

sfuerst said:
Hello, I've written an article at http://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.
The list kind of looks like the typical one brought up by novices,
complaining about things like exceptions and multiple inheritance.
However, the actual issues discussed tend to be more subtle and low-
level than what you are probably thinking. In particular, none of the
"problems" are complaints about the existence of features, just on
their current syntax, or typical underlying implementation.

The 10 problems are:
1) The "new" keyword.
2) Exceptions
3) Implementations of Multiple Inheritance
4) Member Pointers and Member Function Pointers
5) 0 is NULL
6) Operator Overloading
7) Template Syntax
8) The "export" Keyword
9) Classes verses Structs
10) Barriers

Unfortunately, some of the solutions aren't particularly good. (The
worst one probably is a replacement syntax for the new keyword.)
However, constructive criticism has to start somewhere.

Any comments, or flames are welcome. :)

Steven
I am surprised you did not complain about the preprocessor. Ugly and
powerless. No loops, no procedures, no way to tell a macro from a
language keyword or name, no way to even insert a newline into macro
expansion. I wonder why they had to re-invent that particular wheel when
much superior PL/1 preprocessor had been around since 60s.

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?

-Pavel
 
J

James Kanze

* sfuerst:

[...]
OK, there's much wrong.
First, "Unfortunately, the new keyword doesn't allow [...] an
override." is wrong. You override the allocation aspect by
defining operator new (and/or operator new[], which is the
allocation function, which can be overridden per class as well
as overriding the global default (where, to boot, you can
override the action taken on allocation failure via
set_new_handler). And you can "override" the initialization
action by defining suitable constructors.

Not to mention all the things that can be done using placement
new.
Second, this is wrong: "A second problem with the new keyword
is that it combines two different operations in one. The first
is to allocate memory, the second is to initialize it. This
combination means that initializing an array is impossible to
do with anything other than the default constructor."
'new' is designed to very strongly couple allocation and
initialization, with automatic rollback. It's extremely tricky
to do manually, that is, to do it correctly without language
support. If C++ didn't have 'new' to do it, it would need some
other mechanism to do it, which would then be used instead of
'new'.

FWIW: you can separate the two actions, by calling the operator
new function and using placement new for initialization. New
was introduced, however, precisely because it was felt that the
separation is a bad thing---it means that you can end up with
raw memory, that the compiler thinks is a constructed object.
In all but very exceptional, low level code, this is an error.
Also, it's wrong that it's impossible to initialize an array
in other ways than using a default constructor.

That could be considered a default. I'm not sure, but perhaps
the new initialization syntax in C++0x addresses this as well.
For example,
std::vector<int> a( 42, 999 );
Third, this is wrong: "Similarly, destructing an array with
the delete[] operator is inefficient.". delete[] is designed
for maximal efficiency. The trade-offs made to achieve that
efficiency, in particular that the programmer must supply the
knowledge of whether it's delete or delete[] (just in order to
save a byte or two of memory!) is a problem, but the
efficiency is not. :)
Now, to your (rhetorical) question, "If all backwards
compatibility were thrown out, how could construction,
initialization, and memory allocation be better done, (paying
particular attention to orthogonality)?"
This is addressed in C++0x, which unfortunately seems to be a
long way from ratification, but still.
It's an initialization syntax based on curly parentheses
initializers.

Yes, but it doesn't really affect new that much (except for
array new---but I've never found a use for that anyway).
Probably because it wasn't felt that new was broken.
 
W

White Wolf

Pavel said:
I am surprised you did not complain about the preprocessor. Ugly and
powerless. No loops, no procedures, no way to tell a macro from a
language keyword or name, no way to even insert a newline into macro
expansion. I wonder why they had to re-invent that particular wheel when
much superior PL/1 preprocessor had been around since 60s.

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?

I think you have over done it. :)
 
B

Bo Persson

sfuerst said:
Hello, I've written an article at
http://locklessinc.com/articles/10_problems_with_c++/ that is
unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.
The list kind of looks like the typical one brought up by novices,
complaining about things like exceptions and multiple inheritance.
However, the actual issues discussed tend to be more subtle and low-
level than what you are probably thinking. In particular, none of
the "problems" are complaints about the existence of features, just
on
their current syntax, or typical underlying implementation.

The 10 problems are:
1) The "new" keyword.
2) Exceptions

Ok, I'll take on number 2. :)

Constructors is just one reason for exceptions. Overloaded operators
is another one. How would you return your failed code from an
operator+()?



Bo Persson
 
B

Balog Pal

sfuerst said:
Hello, I've written an article at
http://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.

Sorry to spoil the day, but the think reads like a collection of rants
coming from half-educated people collected; and the "possible solutions" are
certainly not there.

I stay with real work made in the field, like

Matthew Wilson
Imperfect C++: Practical Solutions for Real-Life Programming (Paperback)
http://www.amazon.com/Imperfect-Practical-Solutions-Real-Life-Programming/dp/0321228774

I suggest you read it, and discover stuff including the area you tried to
cover...
The list kind of looks like the typical one brought up by novices,
complaining about things like exceptions and multiple inheritance.
However, the actual issues discussed tend to be more subtle and low-
level than what you are probably thinking.

Indeed :) The road goes pretty far.
 
S

sfuerst

* sfuerst:
Hello, I've written an article athttp://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.
The list kind of looks like the typical one brought up by novices,

He he, it certainly does. :)

But kudos (speling?) to you for writing it up.

For that can both help you and help many others.
complaining about things like exceptions and multiple inheritance.
However, the actual issues discussed tend to be more subtle and low-
level than what you are probably thinking.  In particular, none of the
"problems" are complaints about the existence of features, just on
their current syntax, or typical underlying implementation.
The 10 problems are:
1) The "new" keyword.

OK, there's much wrong.

First, "Unfortunately, the new keyword doesn't allow [...] an override." is
wrong. You override the allocation aspect by defining operator new (and/or
operator new[], which is the allocation function, which can be overridden per
class as well as overriding the global default (where, to boot, you can override
the action taken on allocation failure via set_new_handler). And you can
"override" the initialization action by defining suitable constructors.

I think you've missed the point. In other languages, people are able
to globally override memory allocation. This is done for debugging:
To find a memory leak, you can store the file and line of the
allocation call, and see where the allocations that are never freed
come from. Another use is profiling: What sized allocations are your
program repeatedly allocating and freeing? Perhaps the use of some
other allocator other than the default could improve performance.

With C++, you can use the placement new syntax to pass extra
information to an overridden new routine. The problem is that there
is no way to globally cause this to happen, without manually editing
every single call to new in your program. (You can override
individual classes, no problem... but the only available global
overrides are operator new(size_t) and operator new[](size_t), and
these don't let you access the file and line number you need.)

If new was some sort of operator instead of a keyword, and used
brackets to surround the type, then it would be possible to use a
macro to do this. Unfortunately, this isn't the case.

i.e We'd like to do something like:
#ifdef DEBUG_ALLOCATIONS
#define new(T) new(T, __FILE__, __line__)
#endif

Imagine if new was a template... (convert it from a keyword into
something within the standard library),
and then imagine if templates used normal brackets instead of greater
than and less than signs. These "tiny" changes increase the
orthogonality enough that the above becomes possible. Unfortunately,
macros require normal brackets, which is why both changes are
required, rather than just the first.
Second, this is wrong: "A second problem with the new keyword is that it
combines two different operations in one. The first is to allocate memory, the
second is to initialize it. This combination means that initializing an array is
impossible to do with anything other than the default constructor."

'new' is designed to very strongly couple allocation and initialization, with
automatic rollback. It's extremely tricky to do manually, that is, to do it
correctly without language support. If C++ didn't have 'new' to do it, it would
need some other mechanism to do it, which would then be used instead of 'new'.

Also, it's wrong that it's impossible to initialize an array in other ways than
using a default constructor.

For example,

     std::vector<int> a( 42, 999 );

This isn't an array. This is a vector, but I think you know that.
You don't use delete[] with a vector... (Unless you have an array of
vectors. :p )
Of course, I know this is just a nice way of saying that most people
shouldn't use raw arrays. They are out of date, and vectors should be
used instead. If so, this actually makes the insane non-compatible
change easier. The only code that would need to change is that within
Third, this is wrong: "Similarly, destructing an array with the delete[]
operator is inefficient.". delete[] is designed for maximal efficiency. The
trade-offs made to achieve that efficiency, in particular that the programmer
must supply the knowledge of whether it's delete or delete[] (just in order to
save a byte or two of memory!) is a problem, but the efficiency is not. :)

The problem with delete[] is that it exists. You use "delete" with
everything else. Why should arrays be special? Special cases are the
very definition of non-orthogonality.

The basic argument is that if you have an array, you probably know its
size. (vector<> certainly does.) If you don't know its size, then
your code probably has a latent buffer overflow problem, and is highly
likely to be buggy elsewhere. Therefore, there should be no problem
passing that size to some deletion routine when you need to
deconstruct the objects in that array. Of course this would totally
break backwards compatibility... but the whole point of exploring
these things is to look at what is possible if we allow that.

Steven
 
S

sfuerst

Ok, I'll take on number 2.  :)

Constructors is just one reason for exceptions. Overloaded operators
is another one. How would you return your failed code from an
operator+()?

Bo Persson

You are right, basically you are stuck. Exceptions are sometimes the
only way to communicate failure conditions in some cases. However,
the problem with exceptions is not that they exist at all... its that
they provide a poorly documented interface to functions. In theory,
all functions should list what potential exceptions they could throw
as part of their definition / external documented interface. In
practice, this rarely happens. The reason is that far too many
exceptions are possible in any non-trivial code. The combinatorial
explosion would lead to the poor programmer having to do much extra
typing. Thus the argument leads to: we can't get rid of them... but
can we minimize their use? The answer to that is a probable "yes".
If their use is minimized, then the extra typing is minimized... and
enforcing their documentation isn't quite so much of a burden.

In short, wouldn't it be cool if the compiler could guarantee that
your code was exception safe? To do so, it simply needs more
information than what currently is usually provided.
 
B

Bo Persson

sfuerst said:
Third, this is wrong: "Similarly, destructing an array with the
delete[] operator is inefficient.". delete[] is designed for
maximal efficiency. The trade-offs made to achieve that
efficiency, in particular that the programmer must supply the
knowledge of whether it's delete or delete[] (just in order to
save a byte or two of memory!) is a problem, but the efficiency is
not. :)

The problem with delete[] is that it exists. You use "delete" with
everything else. Why should arrays be special? Special cases are
the
very definition of non-orthogonality.

Arrays ARE special! We got that from the C language.

In C++ this is solved by std::vector, which never ever leaks memory.
What is there left to dbug?


Bo Persson
 
B

Balog Pal

I think you've missed the point. In other languages, people are able
to globally override memory allocation. This is done for debugging:
To find a memory leak, you can store the file and line of the
allocation call, and see where the allocations that are never freed
come from. Another use is profiling: What sized allocations are your
program repeatedly allocating and freeing? Perhaps the use of some
other allocator other than the default could improve performance.

With C++, you can use the placement new syntax to pass extra
information to an overridden new routine. The problem is that there
is no way to globally cause this to happen, without manually editing
every single call to new in your program.
<<

TMK there is a bunch of leak detectors out there.
But I never used any of them -- Visual C++ has it built-in for decades. And
all it takes a single #define new debug_new at the front of the source. If
you use it, then you get the source file/line of allocation besides the
leaked block address, size and content.

The last time I had to put together a ehap diagnostic was around '94, even
then I was possibly just not aware of a ready solution...

Manually editing lines of code?

What you ask for, is sitteng there, working, discover how it is done instead
of claiming it impossible.

OTOH, the real way to make correct code is definitely not going by that info
but through using consistent RAII-like handling, and reviews enforcing it.

As test runs will hardly cover all possible paths including errors and
exceptions, so relying on the empty leak list from a random run is nothing
but illusion of being okay. While with trivial style it is easy to make
leaks impossible.

Why invest in better patches instead of cure the problem at roots?



(You can override
individual classes, no problem... but the only available global
overrides are operator new(size_t) and operator new[](size_t), and
these don't let you access the file and line number you need.)

If new was some sort of operator instead of a keyword, and used
brackets to surround the type, then it would be possible to use a
macro to do this. Unfortunately, this isn't the case.

i.e We'd like to do something like:
#ifdef DEBUG_ALLOCATIONS
#define new(T) new(T, __FILE__, __line__)
#endif

Imagine if new was a template... (convert it from a keyword into
something within the standard library),
and then imagine if templates used normal brackets instead of greater
than and less than signs. These "tiny" changes increase the
orthogonality enough that the above becomes possible. Unfortunately,
macros require normal brackets, which is why both changes are
required, rather than just the first.

....
You don't use delete[] with a vector... (Unless you have an array of
vectors. :p )

You should not use delete[] at all, ever. Sending all the related problems
to limbo. (this one is even easy to "review" by grep...)
Of course, I know this is just a nice way of saying that most people
shouldn't use raw arrays. They are out of date, and vectors should be
used instead.

vectors, or other fit collections -- they are easy to find ready to use. And
even writing one is simpler than dealing with the related problems. I'm
sure there is no use case where built-in array would beat them with one
dimension. With multi dim see the relevant chapter in Wilson.
The problem with delete[] is that it exists.

So eradicate it for good. How much of real problem is THAT really?

Especially compared to the can of worms those raw arrays bring, especially
paired with dynamic allocation...
 
A

Alf P. Steinbach

* sfuerst:
* sfuerst:
Hello, I've written an article athttp://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.
The list kind of looks like the typical one brought up by novices,
He he, it certainly does. :)

But kudos (speling?) to you for writing it up.

For that can both help you and help many others.
complaining about things like exceptions and multiple inheritance.
However, the actual issues discussed tend to be more subtle and low-
level than what you are probably thinking. In particular, none of the
"problems" are complaints about the existence of features, just on
their current syntax, or typical underlying implementation.
The 10 problems are:
1) The "new" keyword.
OK, there's much wrong.

First, "Unfortunately, the new keyword doesn't allow [...] an override." is
wrong. You override the allocation aspect by defining operator new (and/or
operator new[], which is the allocation function, which can be overridden per
class as well as overriding the global default (where, to boot, you can override
the action taken on allocation failure via set_new_handler). And you can
"override" the initialization action by defining suitable constructors.

I think you've missed the point. In other languages, people are able
to globally override memory allocation. This is done for debugging:
To find a memory leak, you can store the file and line of the
allocation call, and see where the allocations that are never freed
come from. Another use is profiling: What sized allocations are your
program repeatedly allocating and freeing? Perhaps the use of some
other allocator other than the default could improve performance.

With C++, you can use the placement new syntax to pass extra
information to an overridden new routine. The problem is that there
is no way to globally cause this to happen, without manually editing
every single call to new in your program.

You can just use a macro.

Check out e.g. Microsoft's MFC.

Ugh, I never thought I'd direct *anyone* to MFC, but it does this. There was by
the way an infamous bug related to that macro. They'd originally forgotten to
define placement delete, thus leaking memory when exceptions occurred in debug
builds...

(You can override
individual classes, no problem... but the only available global
overrides are operator new(size_t) and operator new[](size_t), and
these don't let you access the file and line number you need.)

If new was some sort of operator instead of a keyword, and used
brackets to surround the type, then it would be possible to use a
macro to do this. Unfortunately, this isn't the case.

i.e We'd like to do something like:
#ifdef DEBUG_ALLOCATIONS
#define new(T) new(T, __FILE__, __line__)
#endif

You're homing in on one of the solutions, yes. :)


[snip]
Also, it's wrong that it's impossible to initialize an array in other ways than
using a default constructor.

For example,

std::vector<int> a( 42, 999 );

This isn't an array. This is a vector, but I think you know that.
You don't use delete[] with a vector... (Unless you have an array of
vectors. :p )

The example just shows that you can construct elements of an array any way you
wish. There's nothing magical about std::vector. It's just a class that you can
define yourself.


[snip]
Third, this is wrong: "Similarly, destructing an array with the delete[]
operator is inefficient.". delete[] is designed for maximal efficiency. The
trade-offs made to achieve that efficiency, in particular that the programmer
must supply the knowledge of whether it's delete or delete[] (just in order to
save a byte or two of memory!) is a problem, but the efficiency is not. :)

The problem with delete[] is that it exists. You use "delete" with
everything else. Why should arrays be special? Special cases are the
very definition of non-orthogonality.

That's the "byte or two" I mentioned in the quote.

The basic argument is that if you have an array, you probably know its
size. (vector<> certainly does.) If you don't know its size, then
your code probably has a latent buffer overflow problem, and is highly
likely to be buggy elsewhere. Therefore, there should be no problem
passing that size to some deletion routine when you need to
deconstruct the objects in that array. Of course this would totally
break backwards compatibility... but the whole point of exploring
these things is to look at what is possible if we allow that.

Think about a zero-terminated string, and functions like

char const* dup( char const* s )
{
return strcpy( new char[strlen(s)+1], s );
}

That's about "knowing the size", often, as here, you don't even know the size
specified at allocation, but would have to obtain it by e.g. using strlen.


Cheers & hth.,

- Alf
 
D

dragan

Bo Persson said:
Ok, I'll take on number 2. :)

Constructors is just one reason for exceptions. Overloaded operators is
another one. How would you return your failed code from an operator+()?

That's the wrong question to ask though because it pre-supposes exceptions.
The question is, "what are the alternatives?".

1. Don't write code that errors in constructors or operators.
2. Do default error handling instead of requiring propogation via
exceptions: exit(), perhaps.
3. Use another error handling technique.
4. ?

The argument for exceptions goes something like this: Some people want to
write code where errors can happen in constructors and operators, therefore
exceptions were created. Because exceptions were created, why not just go
ahead and use them all over the place.

It's a classic case of the exceptional case (no pun intended, but a little
humourous anyway) botching up the common case.
 
D

dragan

sfuerst said:
Hello, I've written an article at
http://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.

From the article:

"With explicit construction, the zero-argument count, and no-return-value
requirements for a constructor evaporate."

What about compiler-generated temporaries created via a constructor? You
pre-supposed only one pattern of construction: that in which the developer
is writing code. There is not just one pattern of construction to address.
 
D

dragan

sfuerst said:
Hello, I've written an article at
http://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.

From the article:

"As currently implemented, the export keyword cannot speed up compile time.
The repeated work that we try so hard to remove is simply deferred until
link time. This is a disaster, and removes the entire point of having this
feature."


I thought the gist of "export" was to give the ability to hide template
implementation source code. I never thought it's purpose was at all tied to
performance.
 
D

dragan

sfuerst said:
Hello, I've written an article at
http://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.

In the section titled "Implementation of Multiple Inheritence", you just
regurgitated well-known information that can be found in textbooks. The
solution to multiple inheritence is to not do it or only allow a restricted
form of it. Then all that thunking and offsetting simply goes away.
 
D

dragan

sfuerst said:
Hello, I've written an article at
http://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.

From the article: "Why not use this difference between plain-old-data and
more complex objects to define the difference between structs and classes?"

Bjarne and his peers wrestled with that (and probably argued about it a lot
too) when C++ was first designed. Bjarne notes in his book "The Design and
Evolution of C++" (which you should read or read again because you seem to
be oblivious to what was written in that tome) that he thought if he would
have created such a distinction (that is, ANY significant distinction)
between structs and classes that C++ would have been "stillborn". We'll
never know what would have been had structs and classes been fundamentally
different, but the reason why structs and classes are defined as they are is
well-documented.
 
D

dragan

sfuerst said:
Hello, I've written an article at
http://locklessinc.com/articles/10_problems_with_c++/
that is unfortunately way too long to post here, detailing ten
perceived problems with C++, together with some possible solutions.

Passages from the article are enclosed in quotation marks below).

"So the C++ language has quite a few problems."

You say that so matter-of-factly and as if you were trying to persuade
others, perhaps "novices" that the C++ designers "missed something" or
didn't think it over enough before making their design choices or that they
were wrong choices. While a tiny bit of that surely exists, C++ is what it
is for consideration of the "bigger-picture" in which it exists, rather than
in comparison of an apple to an orange. A lot of the "baggage" that C++
carries is BY DESIGN: mostly for C compatibility and compatibility with
legacy C++ code.

"However, they all seem fixable if one were willing to break source and ABI
backwards compatibility."

That would be not in the spirit of C++ and would be instead a new language.
The language D has that charter, I believe. You may want to check it out.

"Hopefully, this has provided constructive criticism, and enough detail in
the solutions proposed to be useful."

While some low-level details you spoke about in your article are news to me
(I program at a much higher level but find information about the
underpinnings an interesting hobby), I highly doubt that in the larger scope
of this newsgroup that you've noted anything that hasn't been analysed a
thousand times before by thousands of other developers and that the C++
committee members don't discuss on a daily basis. (No offense meant).
 
D

dragan

You cannot feasible solve error reporting 10 call frames up without
exceptions, possibly through different libraries, without turning all the
source code into a mess.

Quite easily actually. An example is the new operator's set_new_handler.

I don't have privy to those "large applications" that everyone keeps talking
about, but if I did I'd probably "refactor" them so they wouldn't be so
unwieldly.

OTOH, if you are talking about project issues and the larger scope of
cross-component (by different providers) interoperability, that's a
different argument. Probably one of a pipe dream though since a C++ eco
system to that level isn't going to happen except maybe as a niche. I'd be
interested to hear about some of these large projects that used libraries
from multiple vendors to build large scale applications and how it went. To
me, I would think it would be just making an integration mess since coding
styles with C++ vary so much. And what about duplication? One vendor
considers the standard string to be less than useful so it creates a
proprietary one for use specifically for use with it's library, and then the
next vendor B has quirk X and on and on.
 

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,743
Messages
2,569,478
Members
44,898
Latest member
BlairH7607

Latest Threads

Top