Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

I don't have to tell you...

2 views
Skip to first unread message

Howard Beale

unread,
Nov 24, 2009, 3:40:42 PM11/24/09
to
I don't have to tell you C++ is bad. Everybody knows C++ is bad. It's an
OOP language. Everybody's tired of the STL or scared of using templates. An
hour of coding accomplishes five minutes worth, software companies are
going bust, programmers keep a resume in the desk drawer. Shitty javascript
is running wild on the web and there's nobody anywhere who seems to know
how to code, and there's no end to it. We know iterators are unfit to use
and class heirarchies never work the way they're supposed to, and we sit
watching porn while some blogger tells us that today there were fifteen new
half-ass workarounds for std::vector and sixty-three new things you can't
do with a template, as if that's the way it's supposed to be. We know OOP
is bad -- worse than bad. It's crazy. It's like every programmer everywhere
has gotten lazy, so we don't even attempt to write efficient code anymore.
We sit at the office, and slowly the technology we are creating is getting
crappier, and all we say is, "Please, at least leave our PCs alone. Let me
have my Commodore 64 emulator and my fractals and my original DOOM and I
won't say anything. Just leave us alone." Well, I'm not gonna leave you
alone. I want you to get mad! I don't want you to write a new container
library. I don't want you to start using C# or D. I don't want you to write
to the C++0x working group because I wouldn't know what to tell you to
write.

...

I want you to get up right now, get up, go to your windows, open them and
stick your head out and yell, "I'm as mad as hell and I'm not going to take
C++ anymore!" Things have got to change. But first, you've gotta get mad!

That was kind of fun. But seriously, you should be mad at C++ because it
sucks.

carl

unread,
Nov 24, 2009, 3:53:00 PM11/24/09
to

"Howard Beale" <no...@none.none> wrote in message
news:Xns9CCD8B21AFA...@69.16.186.8...

Hehe

I'm as mad as hell and I'm not going to take C++ anymore!!

http://www.youtube.com/watch?v=q_qgVn-Op7Q&feature=fvst

:-)

Brian

unread,
Nov 24, 2009, 4:24:34 PM11/24/09
to
On Nov 24, 2:40 pm, Howard Beale <n...@none.none> wrote:
> I don't have to tell you C++ is bad. Everybody knows C++ is bad. It's an
> OOP language. Everybody's tired of the STL or scared of using templates. An
> hour of coding accomplishes five minutes worth, software companies are
> going bust, programmers keep a resume in the desk drawer. Shitty javascript
> is running wild on the web and there's nobody anywhere who seems to know
> how to code, and there's no end to it. We know iterators are unfit to use
> and class heirarchies never work the way they're supposed to, and we sit
> watching porn while some blogger tells us that today there were fifteen new
> half-ass workarounds for std::vector and sixty-three new things you can't
> do with a template, as if that's the way it's supposed to be. We know OOP
> is bad -- worse than bad. It's crazy. It's like every programmer everywhere
> has gotten lazy, so we don't even attempt to write efficient code anymore.

I disagree with most of this, but think there's some truth to that
last sentence. A lot of programmers got lazy and stopped paying
attention to efficiency issues.

>
> I want you to get up right now, get up, go to your windows, open them and
> stick your head out and yell, "I'm as mad as hell and I'm not going to take
> C++ anymore!" Things have got to change. But first, you've gotta get mad!
>
> That was kind of fun.  But seriously, you should be mad at C++ because it
> sucks.

I don't claim it is great, but that it is better than the other well-
known languages.


Brian Wood
http://webEbenezer.net

James Kanze

unread,
Nov 25, 2009, 4:58:33 AM11/25/09
to
On Nov 24, 9:24 pm, Brian <c...@mailvault.com> wrote:

> I don't claim it is great, but that it is better than the
> other well- known languages.

C++ is bad. It's just that all of the reasonable alternatives
are worse. (Some one---I don't know who---originally said that
about democracy.)

--
James Kanze

Saeed Amrollahi

unread,
Nov 25, 2009, 6:14:23 AM11/25/09
to

Hi Brian

I am with you.
About laziness, you are right. I think about that a lot.
A lot of people in my company and in my vicinity (Tehran) are lazy in
programming.
Apparently, it is world-wide :( I suspect, we will have programmers
like Ken Thompson or
Brian Kernighan in near future.

Regards,
-- Saeed Amrollahi

Mick

unread,
Nov 25, 2009, 12:20:58 PM11/25/09
to
Churchill, Something like: "Democracy is the worst possible system of
government, apart from all the others we have tried."

Howard Beale

unread,
Nov 25, 2009, 2:48:00 PM11/25/09
to
James Kanze wrote:

> C++ is bad. It's just that all of the reasonable alternatives
> are worse. (Some one---I don't know who---originally said that
> about democracy.)


My personal thoughts (OP here):

Machine code on punch cards was acceptable until something better came
along.

Assembly language added readability and maintainability and was less
error-prone. Assembly language was acceptable until something better
came along.

FORTRAN added readability and maintainability and was less error-prone.

The step from FORTRAN to C was different. C provided more explicit
dealings with pointers, data structures, etc, and was targeted more
towards computer scientists than mathematicians. FORTRAN was (and
remains) a good choice for pure number crunching, e.g. benchmarking
supercomputers. But with C, it became apparent that there was more to
programming than number crunching, and C was the best choice for general
programming.

Up to here, we're still talking about baby steps. Each step just gives
the programmer a little more convenience and a little more power, but we
really haven't gone very far at all from where we started -- machine
code. The translation from C to machine code is very "thin."

The step from C to C++ is not a step at all, it's a giant leap of faith.
C++ is a paradigm shift more than it is a successor to C. In fact, I
believe that the main problems with C++ are a result of its attempt to
still "be" C for the most part, as opposed to just becoming something
entirely new. It attempts to bring OOP to C by just adding a few
keywords and angle brackets here and there.

The translation from C++ to machine code is NOT thin. Things are hidden
from the programmer and, worse, are beyond his or her control. And many
of these are really significant. In what order are constructors and
destructors called? Answer - in whatever order ANSI/ISO chooses to call
them, and you'll never know just by looking at your code, and you'll
never be able to change it if it doesn't suit you. Does it matter? Yes
- the choice that was made means that you should never call virtual
functions from a constructor or destructor, even though the language
will allow you to do so with no warning, just incorrect behavior. On
the other hand, you had better remember to make your destructors virtual
(in some cases), or you'll have memory leaks for some reason that is
entirely invisible when looking at your code. What does a template
really do? Answer - it creates a LOT of code behind the scenes that
you'll never see, but it's purely a compile-time construct, so don't
expect to do any truly elegant polymorphic type things with them.
Operator overloading looks cool at first glance, is it useful? Answer -
in almost every case, NO.

These are just some examples, and some C++ experts are fine with them.
There are ways to work around the shortcomings, usually at the expense
of readability or efficiency.

But my feeling is that class hierarchies, templates, operator
overloading, etc, are the only things that C++ really brings to the
table, and these are the things that don't work like they should! I
might as well use C and have tables of function pointers wherever that
approach is more efficient than a switch statement. Encapsulation and
information hiding? Just write a clean and well documented API.

I don't believe that C is the last step in the evolution of programming
languages and that everything afterward has been a mistake. But I do
feel that C++ was not the right answer.

Alf P. Steinbach

unread,
Nov 25, 2009, 4:05:42 PM11/25/09
to
* Howard Beale:

>
> In what order are constructors and
> destructors called? Answer - in whatever order ANSI/ISO chooses to call
> them, and you'll never know just by looking at your code, and you'll
> never be able to change it if it doesn't suit you. Does it matter? Yes
> - the choice that was made means that you should never call virtual
> functions from a constructor or destructor, even though the language
> will allow you to do so with no warning, just incorrect behavior.

Jeez, where do you pick up such misconceptions?

Cheers & hth.,

- Alf

Howard Beale

unread,
Nov 25, 2009, 8:28:50 PM11/25/09
to
Alf P. Steinbach wrote:

> Jeez, where do you pick up such misconceptions?

What's miconceived?

C++ FAQ [23.5]:
- "When my base class's constructor calls a virtual function on its this
object, why doesn't my derived class's override of that virtual function
get invoked?"
http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5

http://www.artima.com/cppsource/nevercall.html
- "Never Call Virtual Functions during Construction or Destruction"


One could argue that it's good thing for C++ not to allow this, but I'd
simply point out that more recent languages don't have a problem with it:

http://www.andymcm.com/csharpfaq.htm#3.9

Yes, I know that it's recommended (in C#) not to call virtual functions
from constructors / destructors, but it is supported and will work the way
you expect. The danger is just that someone else overriding your virtual
function may unknowingly alter the behavior of construction / destruction.

Alf P. Steinbach

unread,
Nov 25, 2009, 9:37:09 PM11/25/09
to
* Howard Beale:

> Alf P. Steinbach wrote:
>
>> Jeez, where do you pick up such misconceptions?
>
> What's miconceived?
>
> C++ FAQ [23.5]:
> - "When my base class's constructor calls a virtual function on its this
> object, why doesn't my derived class's override of that virtual function
> get invoked?"
> http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5

This is good. It's the official C++ FAQ. Since you're using it as authority I
mention that some of that stuff further down originated with me. :-)


> http://www.artima.com/cppsource/nevercall.html
> - "Never Call Virtual Functions during Construction or Destruction"

This, however, is total bullshit.

In the technical sense, that is.

Thanks for pointing it out!


> One could argue that it's good thing for C++ not to allow this, but I'd
> simply point out that more recent languages don't have a problem with it:
>
> http://www.andymcm.com/csharpfaq.htm#3.9

On the contrary, Java and C# have very dangerous problems with virtual calls
from constructors.

It's one of the most common bugs in Java applications (you can get a subclass
method invoked before the subclass object has been initialized).

In C++ virtual calls from constructors are safe, with one exception, namely a
call of a pure virtual.

The FAQ explains how it works in C++, but just if you don't want to spend on
time on finding that:

In C++, during a constructor of type T, the '*this' object is of most derived
type (dynamic type) T -- so everything works as the author of class T expects,
no matter whether this constructor call originated from some subclass.


> Yes, I know that it's recommended (in C#) not to call virtual functions
> from constructors / destructors, but it is supported and will work the way
> you expect. The danger is just that someone else overriding your virtual
> function may unknowingly alter the behavior of construction / destruction.

It's a bit more dangerous that in Java/C#; see above.

Balog Pal

unread,
Nov 26, 2009, 4:50:02 AM11/26/09
to
"Alf P. Steinbach" <al...@start.no>

>>> Jeez, where do you pick up such misconceptions?
>>
>> What's miconceived?
>>
>> C++ FAQ [23.5]:
>> - "When my base class's constructor calls a virtual function on its this
>> object, why doesn't my derived class's override of that virtual function
>> get invoked?"
>> http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5
>
> This is good. It's the official C++ FAQ. Since you're using it as
> authority I mention that some of that stuff further down originated with
> me. :-)

Mega-LOL.

>> http://www.artima.com/cppsource/nevercall.html
>> - "Never Call Virtual Functions during Construction or Destruction"
>
> This, however, is total bullshit.

It isn't. It's Item#9 form EC++, explains well what is going on really, with
summary "Don't call virtual functions during construction or destruction,
because such calls will never go to a more derived class than that of the
currently executing constructor or destructor."

What quoted above is the item title -- that shall not be used as replacement
of the item content itself. :-o

Do you think a guideline book should add "unless you hit an exception" or
"unless you know better"?

> In C++ virtual calls from constructors are safe, with one exception,
> namely a call of a pure virtual.

Isn't it also safely call terminate() ?


Alf P. Steinbach

unread,
Nov 26, 2009, 8:26:14 AM11/26/09
to
* Balog Pal:

> "Alf P. Steinbach" <al...@start.no>
>>>> Jeez, where do you pick up such misconceptions?
>>>
>>> What's miconceived?
>>>
>>> C++ FAQ [23.5]:
>>> - "When my base class's constructor calls a virtual function on its
>>> this object, why doesn't my derived class's override of that virtual
>>> function get invoked?"
>>> http://www.parashift.com/c++-faq-lite/strange-inheritance.html#faq-23.5
>>
>> This is good. It's the official C++ FAQ. Since you're using it as
>> authority I mention that some of that stuff further down originated
>> with me. :-)
>
> Mega-LOL.
>
>>> http://www.artima.com/cppsource/nevercall.html
>>> - "Never Call Virtual Functions during Construction or Destruction"
>>
>> This, however, is total bullshit.
>
> It isn't. It's Item#9 form EC++,

I don't care about the messenger. The message is bullshit. Really bad advice.
FUD. Even in the context of programming for constrained embedded systems
(there's no connection).

Balog Pal

unread,
Nov 26, 2009, 8:44:09 AM11/26/09
to
"Alf P. Steinbach" <al...@start.no>

>>>> http://www.artima.com/cppsource/nevercall.html
>>>> - "Never Call Virtual Functions during Construction or Destruction"
>>>
>>> This, however, is total bullshit.
>>
>> It isn't. It's Item#9 form EC++,
>
> I don't care about the messenger. The message is bullshit. Really bad
> advice. FUD. Even in the context of programming for constrained embedded
> systems (there's no connection).

I'm confused. Please quote me the part of the message which fits the
description, or elaborate.

Also, which are the situations, when you actually want to actively call
virtuals (the implicit dtor call doesn't count) in the mentioned places? I
failed to think up a sensible example.


Alf P. Steinbach

unread,
Nov 26, 2009, 10:11:51 AM11/26/09
to
* Balog Pal:

> "Alf P. Steinbach" <al...@start.no>
>>>>> http://www.artima.com/cppsource/nevercall.html
>>>>> - "Never Call Virtual Functions during Construction or Destruction"
>>>>
>>>> This, however, is total bullshit.
>>>
>>> It isn't. It's Item#9 form EC++,
>>
>> I don't care about the messenger. The message is bullshit. Really bad
>> advice. FUD. Even in the context of programming for constrained
>> embedded systems (there's no connection).
>
> I'm confused. Please quote me the part of the message which fits the
> description, or elaborate.

Every part of the quoted part is meaningless FUD.

So, I haven't looked at the rest. :-)


> Also, which are the situations, when you actually want to actively call
> virtuals (the implicit dtor call doesn't count) in the mentioned places?

Quite a lot of code does that, though not the with motivation that you describe. :-)

The point is that you don't have to care whether the methods are virtual or not.

In C++ it's safe to call them anyway.


> I failed to think up a sensible example.

Actually I fail to come up with any simple example where I'd use a virtual
member for anything.

But as an abstract example, if a base class has a non-virtual method foo(), that
calls a virtual method bar(), and your derived class T overrides bar(), then in
your T constructor you can call foo and foo's call of bar() ends up in T::bar.

It's a not uncommon scenario. The mentioned bugs in Java programs are mainly due
to this scenario occurring often in actual code. In C++ it's no problem. :-)

Howard Beale

unread,
Nov 26, 2009, 2:12:14 PM11/26/09
to
Alf P. Steinbach wrote:

> * Balog Pal:
>> "Alf P. Steinbach" <al...@start.no>
>>

>> I'm confused. Please quote me the part of the message which fits the
>> description, or elaborate.
>
> Every part of the quoted part is meaningless FUD.
>
> So, I haven't looked at the rest. :-)
>
>
>> Also, which are the situations, when you actually want to actively
>> call virtuals (the implicit dtor call doesn't count) in the mentioned
>> places?
>
> Quite a lot of code does that, though not the with motivation that you
> describe. :-)
>
> The point is that you don't have to care whether the methods are
> virtual or not.
>
> In C++ it's safe to call them anyway.


I'm sorry, I can't spot anywhere in this thread where you point out
what's wrong with the original claim... which is supported by the FAQ
(which you apparently helped write) and that article (which I chose
simply because it was the first hit returned by Google on the subject).

If you have a base class "shape" and derived classes "square,"
"circle," and "rectangle," and declare this in shape:

virtual std::string GetName() { return "shape"; }
virtual float GetArea() { return 0; }
virtual ~shape()
{
cout << "Just destroyed a " << GetName()
<< " with area " << GetArea() << endl;
}

and if your circle class has this:

std::string GetName() { return "circle"; }
float GetArea() { return 3.14f * r * r; }

The output when a circle is deleted will be:

"Just destroyed a shape with area 0"

And the reason for this behavior is exactly what I originally said.

Gert-Jan de Vos

unread,
Nov 26, 2009, 3:07:05 PM11/26/09
to
On Nov 26, 8:12 pm, Howard Beale <n...@none.none> wrote:
> I'm sorry, I can't spot anywhere in this thread where you point out
> what's wrong with the original claim...  which is supported by the FAQ
> (which you apparently helped write) and that article (which I chose
> simply because it was the first hit returned by Google on the subject).
>
> If you have a base class "shape" and derived classes "square,"
> "circle," and "rectangle," and declare this in shape:
>
>   virtual std::string GetName() { return "shape"; }
>   virtual float GetArea() { return 0; }
>   virtual ~shape()
>   {
>     cout << "Just destroyed a " << GetName()
>     << " with area " << GetArea() << endl;
>   }
>
> and if your circle class has this:
>
>   std::string GetName() { return "circle"; }
>   float GetArea() { return 3.14f * r * r; }
>
> The output when a circle is deleted will be:
>
>   "Just destroyed a shape with area 0"
>
> And the reason for this behavior is exactly what I originally said.

I'm not sure what your "original claim" is. I see mostly a rant and
some random not-supported claims about C++ features. Anyway, your
example makes perfect sense:

Your shape base class destructor reports that it just destroyed a
concrete shape. It did, therefore the concrete shape itself does not
exist anymore by the time you get there and there is nothing it can
do. C++ protects you here by making the dynamic behavior of your shape
now that of shape itself, that's all you have. Whether you like it or
not.

Joshua Maurice

unread,
Nov 26, 2009, 3:30:20 PM11/26/09
to
Now, I know you're just trolling, but I'm easily baited.

On Nov 24, 12:40 pm, Howard Beale <n...@none.none> wrote:
> I don't have to tell you C++ is bad. Everybody knows C++ is bad. It's an
> OOP language.

> Everybody's tired of the STL or scared of using templates.

Really? I like the STL for the most part. It saves a huge amount of
time that I would otherwise have to spend maintaining my own container
library, and actual implementations are probably much more efficient
than anything I could write, partly because the better interfaces (aka
iterators), and partly because you have programmers who read the
journals on the latest techniques on algorithms.

> An hour of coding accomplishes five minutes worth, software companies
> are going bust, programmers keep a resume in the desk drawer.

I don't know where you're pulling this from. Your ass maybe? I'm
pretty sure there are many, many, successful companies who still use C+
+. Some might argue that Java et al are replacing C++, but there are
still many domains which C++ will be used for a long time, eg: games
and other performance critical code.

> We know iterators are unfit to use

What? I know of some people who complain that ranges should have been
used instead, but I assume this is not the argument you are making.
What is your alternative to the easy-to-use iterators which allow
generic algorithms on disparate kinds of containers? What makes
iterators unfit to use?

> class heirarchies never work the way they're supposed to,

What?

Alf P. Steinbach

unread,
Nov 26, 2009, 4:09:46 PM11/26/09
to
* Howard Beale:

> Alf P. Steinbach wrote:
>
>> * Balog Pal:
>>> "Alf P. Steinbach" <al...@start.no>
>>>
>>> I'm confused. Please quote me the part of the message which fits the
>>> description, or elaborate.
>> Every part of the quoted part is meaningless FUD.
>>
>> So, I haven't looked at the rest. :-)
>>
>>
>>> Also, which are the situations, when you actually want to actively
>>> call virtuals (the implicit dtor call doesn't count) in the mentioned
>>> places?
>> Quite a lot of code does that, though not the with motivation that you
>> describe. :-)
>>
>> The point is that you don't have to care whether the methods are
>> virtual or not.
>>
>> In C++ it's safe to call them anyway.
>
>
> I'm sorry, I can't spot anywhere in this thread where you point out
> what's wrong with the original claim... which is supported by the FAQ
> (which you apparently helped write) and that article (which I chose
> simply because it was the first hit returned by Google on the subject).


You made several factually incorrect claims, as I count it four of them in the
single paragraph of yours that I quoted in my first response:

* Howard Beale:
> In what order are constructors and destructors called? Answer - in

> whatever order ANSI/ISO chooses to call them, and [1] you'll never know
> just by looking at your code, and [2] you'll never be able to change it


> if it doesn't suit you. Does it matter? Yes - the choice that was

> made means that [3] you should never call virtual functions from a
> constructor or destructor, even though [4] the language will allow you to


> do so with no warning, just incorrect behavior.

To which of these four incorrect claims (if any) are you referring?

None of them are supported by the FAQ.

By the way, the FAQ has many contributors. Many of the regulars in this group
have contributed to it. But it's penned exclusively by Marshall Cline. :-)


> If you have a base class "shape" and derived classes "square,"
> "circle," and "rectangle," and declare this in shape:
>
> virtual std::string GetName() { return "shape"; }
> virtual float GetArea() { return 0; }
> virtual ~shape()
> {
> cout << "Just destroyed a " << GetName()
> << " with area " << GetArea() << endl;
> }
>
> and if your circle class has this:
>
> std::string GetName() { return "circle"; }
> float GetArea() { return 3.14f * r * r; }
>
> The output when a circle is deleted will be:
>
> "Just destroyed a shape with area 0"
>
> And the reason for this behavior is exactly what I originally said.

This illustrates that calling virtuals in C++ destructors is safe and yields a
well-known predictable effect. When the 'shape' destructor executes there's no
longer any 'circle' sub-object. It would be generally undefined behavior if a
call was made down on that non-existing sub-object, and C++ guarantees that that
doesn't happen for an ordinary virtual call: the 'shape' programmer knows
exactly what will happen, and does not have to worry about any 'circle' class.

Balog Pal

unread,
Nov 26, 2009, 5:19:29 PM11/26/09
to
"Alf P. Steinbach" <al...@start.no>
>>>>>> http://www.artima.com/cppsource/nevercall.html
>>>>>> - "Never Call Virtual Functions during Construction or Destruction"
>>>>>
>>>>> This, however, is total bullshit.
>>>>
>>>> It isn't. It's Item#9 form EC++,
>>>
>>> I don't care about the messenger. The message is bullshit. Really bad
>>> advice. FUD. Even in the context of programming for constrained embedded
>>> systems (there's no connection).
>>
>> I'm confused. Please quote me the part of the message which fits the
>> description, or elaborate.
>
> Every part of the quoted part is meaningless FUD.
>
> So, I haven't looked at the rest. :-)

And doing so you flushed the baby with the bathwater. FUD is something that
puts down a claim and either not include rationale at all or creates a phony
one. You shouldn't address content such without reading it.

> The point is that you don't have to care whether the methods are virtual
> or not.
> In C++ it's safe to call them anyway.

...


> But as an abstract example, if a base class has a non-virtual method
> foo(), that calls a virtual method bar(), and your derived class T
> overrides bar(), then in your T constructor you can call foo and foo's
> call of bar() ends up in T::bar.
>
> It's a not uncommon scenario. The mentioned bugs in Java programs are
> mainly due to this scenario occurring often in actual code. In C++ it's no
> problem. :-)

It *IS* a problem. One you appear to miss entirely, or turn a blind eye.

The problem is not of the nature you argue against. Technically the call
works, and what it does is fully defined. And what happens (IMO) makes more
sense too, than say in java.

The problem is a human one -- when calls to virtuals are done, directly or
indirectly, the expectation is they end up in the most derived object. In
the real-life and not the technical sense. People are (appear) just not
aware that in ctor and dtor different rules apply, and expect the code just
work by magic -- as it does in every other context.

The thing is on the FAQ is exactly for that: too many tried and got
surprized. Or even call 'foul' for calling the 'wrong' function. The
fact that we know tha language rules, and can apply sense to say what is the
'right' function technicly will NOT make it correct in the code -- that
*expects* a different behavior. That expectation will not go away by
deducing it as like-impossible to implement either.

> It's a not uncommon scenario. The mentioned bugs in Java programs are
> mainly due to this scenario occurring often in actual code. In C++ it's no
> problem. :-)

In java the manifest problem is dealing with half-baked object in the
expected function.
In C++ it manifests by arriving in Self::foo(). What is way easier to
discover and rearrange the design.

The usual rearrangement is to pass the work up, and make the result of the
former virtual call a parameter of the ctor...
And for dtors you sigh, and copy the code in the derived dtors...

In both cases the call to virtual gets removed from the code, like obeying
the "don't". :)

Alf P. Steinbach

unread,
Nov 26, 2009, 5:57:36 PM11/26/09
to
* Balog Pal:

The incompetence of experienced people is a problem with no known solution.

You say that at least some people, and I assume that you mean experienced ones,
expect the language to behave in a nonsensical way, like some other language
they're familiar with.

And it seems that you're implicitly arguing that because of their nonsensical
expectation the safe behavior is a problem.

That since they practically can't be made competent, the language should be
dumbed down to their level, removing safety features they fail to understand.

Hello.


> In the real-life and not the technical sense. People are
> (appear) just not aware that in ctor and dtor different rules apply, and
> expect the code just work by magic -- as it does in every other context.
>
> The thing is on the FAQ is exactly for that: too many tried and got
> surprized. Or even call 'foul' for calling the 'wrong' function.

No, the FAQ is mainly for novices.

A novice may expect C++ to work like some other language, e.g. like Java.

An experienced C++ programmer who expects that, however, is incompetent.


> The fact that we know tha language rules, and can apply sense to say
> what is the 'right' function technicly will NOT make it correct in the
> code -- that *expects* a different behavior. That expectation will not
> go away by deducing it as like-impossible to implement either.

I have on some occasions dumbed down code so that it "should" be grokkable even
by idiots.

But I no longer believe that that is a good idea, I now believe that what I with
good intentions did was actually "evil".

The incompetents remain as confused and dazed as ever, and anyone competent who
doesn't labor from a similar misconception that incompetents can be accomodated,
will just think that the one who wrote the code was in that category -- or
waste time trying to figure out why things weren't done in more idiomatic ways.


>> It's a not uncommon scenario. The mentioned bugs in Java programs are
>> mainly due to this scenario occurring often in actual code. In C++
>> it's no problem. :-)
>
> In java the manifest problem is dealing with half-baked object in the
> expected function.
> In C++ it manifests by arriving in Self::foo(). What is way easier to
> discover and rearrange the design.

You don't want to rearrange the correctly working C++ code.

So, C++: zero time.

Fixing the Java code takes some time.


> The usual rearrangement is to pass the work up, and make the result of
> the former virtual call a parameter of the ctor...
> And for dtors you sigh, and copy the code in the derived dtors...

This doesn't make sense. It seems you have some problem and some particular
based-on-misconceptions non-working solution to that problem in mind. Don't
blame that on the language: blame it on a fixation on a non-working solution.

Not knowing the exact problem I can't help you with that, however.


> In both cases the call to virtual gets removed from the code, like
> obeying the "don't". :)

What you're saying seems to be that you have suffered from the "C++ works like
Java" misconception, and fixed that by removing calls that you believed would
end up in a derived class.

Well that's not something to blame C++ for.

Rather, in that case you learned something new and better. :-)

Balog Pal

unread,
Nov 26, 2009, 6:54:04 PM11/26/09
to
"Alf P. Steinbach" <al...@start.no>

> The incompetence of experienced people is a problem with no known
> solution.
>
> You say that at least some people, and I assume that you mean experienced
> ones, expect the language to behave in a nonsensical way, like some other
> language they're familiar with.

I don't say that. :) The observation is that people just drop in the
virtual call. And start to thinker on the language behavior after getting
burnt.

And not necessarily "expect" the thing work this or that way. The pragmatic
way is to do the work anyway instead of dreaming about a different world. :)

Guidelines just help to minimize the wasted time. Not going there in the
first place or having the relevant info faster at least.

> And it seems that you're implicitly arguing that because of their
> nonsensical expectation the safe behavior is a problem.
>
> That since they practically can't be made competent, the language should
> be dumbed down to their level, removing safety features they fail to
> understand.

That's shadow-boxing. ;-)

I don't have a problem of how C++ deals with virtuals, and most likely would
chose the same behavior. And I also agree with the guideline that states
don't call virtuals in the situation.

Those who are competent and found the rare situation it makes sense or is is
just safely irrelevant will hardly be bothered by it.

>> In the real-life and not the technical sense. People are (appear) just
>> not aware that in ctor and dtor different rules apply, and expect the
>> code just work by magic -- as it does in every other context.
>>
>> The thing is on the FAQ is exactly for that: too many tried and got
>> surprized. Or even call 'foul' for calling the 'wrong' function.
>
> No, the FAQ is mainly for novices.
>
> A novice may expect C++ to work like some other language, e.g. like Java.
>
> An experienced C++ programmer who expects that, however, is incompetent.

Sure. This has nothing to do with the point I made.

I am competent in programming and C++. I do know the behavior of virtuals.
Including this thing. I know it for ages, and at the pioneering period
worked even with the assy code of ctors/dtors. To know the exact point where
the VMT pointer is replaced (effectively changing the actial type of the
object at hand).

Yet, I recall at least one situation from my work I got hit by the related
problem -- having the wrong (meaning not the *intended*) function called
form a base destructor. Wasn't a big deal, and realized it in the first run
(probably it was a pure virtual with a noisy report).

But well demonstrates that shit just happens. ;-))

> I have on some occasions dumbed down code so that it "should" be grokkable
> even by idiots.

We know that is a futile effort, as nature immediately creates an advanced
idiot. And starts cloning it too.

>>> It's a not uncommon scenario. The mentioned bugs in Java programs are
>>> mainly due to this scenario occurring often in actual code. In C++ it's
>>> no problem. :-)
>>
>> In java the manifest problem is dealing with half-baked object in the
>> expected function.
>> In C++ it manifests by arriving in Self::foo(). What is way easier to
>> discover and rearrange the design.
>
> You don't want to rearrange the correctly working C++ code.
> So, C++: zero time.

Computers do what is ordered, not what was intended. The "correct" code
would be with the intended behavior. The fact that the C++ part safely does
the unintended thing will not make it fly.

>> The usual rearrangement is to pass the work up, and make the result of
>> the former virtual call a parameter of the ctor...
>> And for dtors you sigh, and copy the code in the derived dtors...
>
> This doesn't make sense. It seems you have some problem and some
> particular based-on-misconceptions non-working solution to that problem in
> mind. Don't blame that on the language: blame it on a fixation on a
> non-working solution.

You can put it that way if you like, it won't make the problem go away.
The mind works in an interesting way. See the examples of the optical
illusions. (or how is that called when you see straight lines as curved,
equal length as different, same color as massively darker in a properly
created picture).

Similar fallacy is to expect things to "work". There was recently a
reference to Mark Rosewater's evil creations here or on a neighboring forum.
And that is exactly true.

And the more commonly a feature just does the job the less we think there
are limits.

>> In both cases the call to virtual gets removed from the code, like
>> obeying the "don't". :)
>
> What you're saying seems to be that you have suffered from the "C++ works
> like Java" misconception, and fixed that by removing calls that you
> believed would end up in a derived class.
>
> Well that's not something to blame C++ for.

That is what I'm saying from the start. This problem is not related to C++,
but to the general thinking of virtuals. And a related genuine, theoretic
limitation.

Languages could create different behaviors, but none of them would be good
for all the cases.


Howard Beale

unread,
Nov 27, 2009, 1:19:02 AM11/27/09
to
Alf P. Steinbach wrote:

> * Howard Beale:
>> Alf P. Steinbach wrote:
>>
>>> * Balog Pal:

> You made several factually incorrect claims, as I count it four of
> them in the single paragraph of yours that I quoted in my first
> response:
>
> * Howard Beale:
>> In what order are constructors and destructors called? Answer - in
>> whatever order ANSI/ISO chooses to call them, and [1] you'll never
>> know just by looking at your code, and [2] you'll never be able to
>> change it
>> if it doesn't suit you. Does it matter? Yes - the choice that was
>> made means that [3] you should never call virtual functions from a
>> constructor or destructor, even though [4] the language will allow
>> you to do so with no warning, just incorrect behavior.
>
> To which of these four incorrect claims (if any) are you referring?
>
> None of them are supported by the FAQ.

Well, most of them don't need to be supported by anything, as they are
common knowledge.

[1] As in the example I gave (and any example that could be given), you
wouldn't know, by just looking at the code, that you're going to get the
wrong output. You would have to also know about the order in which
constructors / destructors are called, which is exactly what is at issue
here. You may say that the output isn't "wrong," but I personally
believe that if the area of a circle is pi*r^2 during its entire
existence, then it's area should also be pi*r^2 when it is being created
or destroyed. And most programmers, unaware of this little gotcha,
would say the same thing. You, being a C++ proponent and expert, know
differently, but most programmers prefer consistent behavior. Yes, I'll
grant that programmers also want safety, but it is entirely possible for
a compiler to safely allow virtual methods during construction and
destruction.

[2] Do you know of a way to change the order in which constructors /
destructors are called? I don't, outside of writing a new compiler.

[3] I guess "never" is a strong word, so I can meet you half way on this
statement, I suppose, and just say "don't expect virtual methods to work
correctly when called from a constructor or destructor, so call them
there only if you want incorrect behavior." Seems like a silly caveat.
If you feel that the behavior that I describe isn't "incorrect," then
you're too tolerant in your definition of correctness.

[4] My compiler doesn't give me any warning when I call a virtual method
from a constructor or destructor. I don't know what more to tell you.

Howard Beale

unread,
Nov 27, 2009, 1:19:19 AM11/27/09
to
Joshua Maurice wrote:

> Now, I know you're just trolling, but I'm easily baited.

... and also unaware of the movie "Network." It was a goof on a famous
speech in that movie. It was mostly exaggeration and silliness. The first
reply to it included a link to the video. But what I said at the end,
after the speech, was sincere.

Alf P. Steinbach

unread,
Nov 27, 2009, 2:16:06 AM11/27/09
to

I'm not sure what you mean by "wrong output".

You gave an incomplete example. From the output you asserted I and one other
guessed what the missing parts would have to be. That seems to indicate that it
isn't hard at all to relate C++ code to effect and vice versa, re these issues.

Regarding values of member variables or sub-objects, they simply do not exist
before creation or after destruction.

> And most programmers, unaware of this little gotcha,
> would say the same thing. You, being a C++ proponent and expert, know
> differently, but most programmers prefer consistent behavior.

The behavior in C++ is fully consistent.

It would be erronous to invoke methods on a chunk of memory that doesn't satisfy
the assumptions of the methods.

That's what happens in e.g. Java.

And so during T construction and destruction the most derived class, the
object's dynamic type, is T. That's because during construction, any more
derived type's subobject has not yet been initialized, and so doesn't formally
exist, it's just raw memory. And during destruction, any more derived type's
subobject has already been destroyed, hence doesn't formally exist any more.

So the C++ rule is extremely simple: at any time a virtual call invokes the most
derived class' implementation of the method.

The calls are virtual.

And they go to the correct place at any time.


> Yes, I'll
> grant that programmers also want safety, but it is entirely possible for
> a compiler to safely allow virtual methods during construction and
> destruction.

C++ does allow virtual calls during construction and destruction.

What's more, C++ actively supports such calls.

It's possible that you have some misconception that calls are not virtual during
construction and destruction, but they are. The only thing you have to keep in
mind is what exist at these point. Happily C++ won't let you do the Wrong Thing.

Post-construction and pre-destruction is however a bit hard to arrange in C++,
and some people, in particular Andrei Alexandrescu, have argued that it should
be made much easier and automated (e.g. you get into this issue with certain
GUIs like X11).

I'm not sure about that. I think making it much easier would lead to it being
employed for general two-phase construction and destruction by those who tend to
choose the short time-frame easy way. Sort of like making goto easier.


> [2] Do you know of a way to change the order in which constructors /
> destructors are called? I don't, outside of writing a new compiler.

Constructors and destructors are called in a very well defined sequence, except
for what's known as the "static initialization fiasco".

Apart from that issue you specify the construction/destruction order by
declaration order.

When that doesn't suffice you use dynamic allocation.

If you have any particular example/problem, why don't you post it.


> [3] I guess "never" is a strong word, so I can meet you half way on this
> statement, I suppose, and just say "don't expect virtual methods to work
> correctly when called from a constructor or destructor, so call them
> there only if you want incorrect behavior." Seems like a silly caveat.
> If you feel that the behavior that I describe isn't "incorrect," then
> you're too tolerant in your definition of correctness.

It's not a question of feeling.

It's incorrect to invoke methods on non-existent objects.

The behavior you crave, undefined behavior, is simply incorrect by any
reasonable measure of correctness.


> [4] My compiler doesn't give me any warning when I call a virtual method
> from a constructor or destructor. I don't know what more to tell you.

The compiler shouldn't warn you. You're not doing anything wrong (at least as
you describe it!). It's well-defined in C++.

Howard Beale

unread,
Nov 27, 2009, 3:44:18 AM11/27/09
to
Alf P. Steinbach wrote:

>> [1] As in the example I gave (and any example that could be given),
>> you wouldn't know, by just looking at the code, that you're going to
>> get the wrong output. You would have to also know about the order in
>> which constructors / destructors are called, which is exactly what is
>> at issue here. You may say that the output isn't "wrong," but I
>> personally believe that if the area of a circle is pi*r^2 during its
>> entire existence, then it's area should also be pi*r^2 when it is
>> being created or destroyed.
>
> I'm not sure what you mean by "wrong output".
>
> You gave an incomplete example.

It was complete enough to make the point -- in fact, the example wasn't
even needed to make the point. The statement *is* the point:

>> if the area of a circle is pi*r^2 during its entire existence, then
>> it's area should also be pi*r^2 when it is being created or
>> destroyed.

C++ gives us the notion of "objects" that mimic objects in the real,
physical world. I just want a circle to always act like a circle and a
square to always act like a square without having to hack around
arbitrary decisions that were made by someone else. If you don't want
that, fine. You're free to always drive exactly the speed limit, too,
if you feel that the rules invented by someone else are the way that it
must always be.


> Regarding values of member variables or sub-objects, they simply do
> not exist before creation or after destruction.

Only because that's the way the standard says it must be done, which,
*again*, is the point I've been making from the start. The fact that
constructors and destructors even exist is just a choice made in the
standard.


> So the C++ rule is extremely simple: at any time a virtual call
> invokes the most derived class' implementation of the method.

We all know the rule, it's been stated a dozen times here. I believe I
was the first to point it out using the FAQ plus an additional article
that you called FUD. No one needs to have the rule explained any more.


>> [2] Do you know of a way to change the order in which constructors /
>> destructors are called? I don't, outside of writing a new compiler.
>
> Constructors and destructors are called in a very well defined
> sequence, except for what's known as the "static initialization
> fiasco".

I refuse to believe that this far into this discussion, you really need
me to explain that I'm talking about constructors and destructors within
a class hierarchy, and not construction of unrelated global objects.
Come on.


> If you have any particular example/problem, why don't you post it.

I stated the problem multiple times, gave an example, and explained
exactly what it is about the behavior that I dislike. I'm not the only
programmer who dislikes it. If you don't want to talk about it, then
just say "I don't want to talk about it" or just stop posting. There is
no need to defend your knowledge on the topic. No one has questioned it
or even disagreed over what the rules of C++ are.


>> [3] ...


>
> It's not a question of feeling.

Yes, it is. C++ was created by people who felt that the compiler should
behave in a certain way. If they had felt instead that virtual methods
should behave the same way during construction and destruction as they
do at all other times, then they could have written the specification
that way. Yes, the way the behavior is currently specified is
consistent. So what? ANSI could also say that all functions must
always return zero. That's very consistent behavior and if that was the
rule, then it would be "expected" and no one would be surprised by it.
But if someone came along and said "it might be nice for functions to
return non-zero values," would you just quote the spec and say that it's
consistent and expected like you're doing now? Would it matter that it
really *would* be nice for functions to return non-zero values?

The matter of what C++ actually *does* is not a question of feeling, as
you have pointed out over and over again. Please don't point it out
again. It is not being debated here, it never was, it doesn't need to
be.


>> [4] My compiler doesn't give me any warning...


>
> The compiler shouldn't warn you. You're not doing anything wrong (at
> least as you describe it!). It's well-defined in C++.

No, I'm not doing anything wrong, but C++ is.

There are lots of warnings that are given when nothing is wrong, just to
point out that you may get some unexpected behavior if you're not
careful, even though the behavior is well-defined.

Alf P. Steinbach

unread,
Nov 27, 2009, 5:02:05 AM11/27/09
to
* Howard Beale:
> [nonsense]
>

I'm sorry that I didn't notice he was trolling.

- Alf

Balog Pal

unread,
Nov 27, 2009, 5:18:12 AM11/27/09
to
"Howard Beale" <no...@none.none>

>>> if the area of a circle is pi*r^2 during its entire existence, then
>>> it's area should also be pi*r^2 when it is being created or
>>> destroyed.
>
> C++ gives us the notion of "objects" that mimic objects in the real,
> physical world. I just want a circle to always act like a circle and a
> square to always act like a square without having to hack around
> arbitrary decisions that were made by someone else.

And I guess you also expect a house to be created that way too, jumping out
of thin air complete. In reality it is also constructed and in that period
it stays around without roof, walls, windows, etc.

> If you don't want that, fine.

Life rarely considers what we want. :-o We have what we have. A
circle-under-counstruction is NOT a circle-complete. Same goes for
circle-being-destroyed. If it is drawn on paper, you can see the same
thing.

> You're free to always drive exactly the speed limit, too,
> if you feel that the rules invented by someone else are the way that it
> must always be.

Or you can go and vore the value of pi into a law as some bunch of
politicians did. O,O

But really, what would be the alternative of construction? I observed it as
a fundamental approach. SICP suggests the same.

> I stated the problem multiple times, gave an example, and explained
> exactly what it is about the behavior that I dislike. I'm not the only
> programmer who dislikes it.

Ok, we all dislike it. Really. But what should be the alternative? Which
solution we would NOT dislike?

Doing the "intended thing" would require telepathy. No less. It would
require to select some aprt of code of the base destructor and run it
sometimes during the derived destructor's body executes. In general there
is no way for the compiler to figure out which part to take and where to put
it.

Another alternative is to forbid virtual calls outside the object's
lifetime.
- making it compile-time error, just by appearance
-- that needs a completely different build model than C++ has. The
compiler should create a full call tree from dtor, and see all the executed
code. Say goodbye to modules, and ability to implement functions in a
different source file. Also that invlaidates code that would call the
virtual on different branches than actually called from the dtor. (similar
problem as nothrow-check of dtors...)

- making it runtime error
-- so insert special instrumentation code just to check for the
possibility; that would likely hit normal performance. Also I doubt a
runtime error would make too many people happy.

And though I don't know any reasonable use of such call, so think it rare,
there may be cases where people use it by the current behavior, or wanted
exactly that way -- forbidding would hurt them.


The decision made for C++ design looks like a fair compromise. What would
YOU do instead?

>>> [4] My compiler doesn't give me any warning...
>>
>> The compiler shouldn't warn you. You're not doing anything wrong (at
>> least as you describe it!). It's well-defined in C++.
>
> No, I'm not doing anything wrong, but C++ is.
>
> There are lots of warnings that are given when nothing is wrong, just to
> point out that you may get some unexpected behavior if you're not
> careful, even though the behavior is well-defined.

For the reasons just said, the compiler can't give you a consistent warning.
But there are static code analysis tools (like Coverity) that I'd bet can
give you that very warning. Don't ask the price in time or money though.

It could flag some blatant cases, but if the more elaborate ones are missed
that could easily create a false-security situation.

TANSTAAFL


Bo Persson

unread,
Nov 27, 2009, 11:42:19 AM11/27/09
to

Why, oh why, should the base class constructor be bothered to call
code in the derived class?

That is the responsiblity of the derived class' constructor, which
will no doubt be executed a microsecond later.

>
> The thing is on the FAQ is exactly for that: too many tried and got
> surprized. Or even call 'foul' for calling the 'wrong' function.
> The fact that we know tha language rules, and can apply sense to
> say what is the 'right' function technicly will NOT make it correct
> in the code -- that *expects* a different behavior. That
> expectation will not go away by deducing it as like-impossible to
> implement either.
>> It's a not uncommon scenario. The mentioned bugs in Java programs
>> are mainly due to this scenario occurring often in actual code. In
>> C++ it's no problem. :-)
>
> In java the manifest problem is dealing with half-baked object in
> the expected function.
> In C++ it manifests by arriving in Self::foo(). What is way easier
> to discover and rearrange the design.
>
> The usual rearrangement is to pass the work up, and make the result
> of the former virtual call a parameter of the ctor...
> And for dtors you sigh, and copy the code in the derived dtors...

Why? Why can't the destructor of the derived class take care of it's
own destruction?

That is its responsibility!


Bo Persson


Balog Pal

unread,
Nov 27, 2009, 12:18:17 PM11/27/09
to
"Bo Persson" <b...@gmb.dk>

>> The usual rearrangement is to pass the work up, and make the result
>> of the former virtual call a parameter of the ctor...
>> And for dtors you sigh, and copy the code in the derived dtors...
>
> Why? Why can't the destructor of the derived class take care of it's own
> destruction?
>
> That is its responsibility!

Should be obvious. Having class D : public D the order of stuff in
construction is:

1. construct B members
2. execute B body
3. construct D members
4. execute D body

destruction is the mirror.

You call virtual function sometime during (2). And expect it to work in an
environment that would exist at (4). That could only happen if the code part
in question was actually executed magically interleaved with other things in
(4).


Howard Beale

unread,
Nov 27, 2009, 12:54:07 PM11/27/09
to
Alf P. Steinbach wrote:

> [Now that I've been asked not to just explain the spec, I don't want to
> talk about it any more]

Perfectly acceptable.

Howard Beale

unread,
Nov 27, 2009, 1:16:46 PM11/27/09
to
Balog Pal wrote:

>> If you don't want that, fine.
>
> Life rarely considers what we want. :-o We have what we have. A
> circle-under-counstruction is NOT a circle-complete. Same goes for
> circle-being-destroyed. If it is drawn on paper, you can see the same
> thing.

Good point. We're talking about a problem with OOP in general. And
maybe the answer is that OOP isn't "what we want." We're talking about
defining a programming language -- made by us, made for us, so "what we
want" really does matter in this case. You're basically saying "we
invented C++ and it didn't pan out as well as we might have hoped, so
we're stuck with it."


> But really, what would be the alternative of construction? I observed
> it as a fundamental approach. SICP suggests the same.

There are plenty of languages (paradigms) that don't invlove
constructors. C, which is where this discussion started, is a great
example.


> Ok, we all dislike it. Really. But what should be the alternative?
> Which solution we would NOT dislike?

Well, that's why we all come to usenet. To battle trolls and once in a
blue moon, answer a worthwhile question like the one you just re-asked.


> Doing the "intended thing" would require telepathy. No less. It would
> require to select some aprt of code of the base destructor and run it
> sometimes during the derived destructor's body executes. In general
> there is no way for the compiler to figure out which part to take and
> where to put it.

Not really... You could leave it up to the programmer to explicitly
decide the order of construction. If they screw things up and mess
around with uninitialized memory, they get what they paid for. But at
least the decision would be the programmer's, not the compiler's.


> Another alternative is to forbid virtual calls outside the object's
> lifetime.
> - making it compile-time error, just by appearance

> - making it runtime error

These are possibilities... They feel a bit like band-aids, though, and
have drawbacks as you point out.


> The decision made for C++ design looks like a fair compromise. What
> would YOU do instead?

I do have an idea that I think is rather clever. It addresses all the
issues that I originally pointed out (class hierarchies, templates,
operator overloading), and not just the one subtlety of the "virtual"
keyword that drew so much attention in this thread.

I could go into it, but the horse feels a bit dead at this point.
Besides, I'm just another troll with an idea for creating his own
language. If anyone really needs to know about my fabulous idea, I
could go over it, but I'm equally fine with shutting up about it at this
point.

Pavel

unread,
Nov 27, 2009, 1:47:23 PM11/27/09
to
Because

1. It is what the user wants and the compiler has enough information to
generate this code and thereby satisfy the user (the information about
object of which most derived class is actually being created is known at
compile time). Note: if what the user wants is to call the base class's
virtual function, s/he can always force it by explicit qualification.

2. It allows more efficient implementation (the known-to-me C++
implementations first write a pointer to virtual table of the base class
to the object; then override it with the pointer to derived class's
table; this is unnecessary and unjustified overhead breaking the promise
of C++ to be as efficient as possible)

3. The promise of C++ to be as powerful and dangerous to allow the
programmer to blow up his/her entire leg is broken.

4. It is proven to work (by Java for example).


>
> That is the responsiblity of the derived class' constructor, which
> will no doubt be executed a microsecond later.
>

...

> Bo Persson
>
>

Krice

unread,
Nov 27, 2009, 2:26:50 PM11/27/09
to
On 27 marras, 20:16, Howard Beale <n...@none.none> wrote:
> We're talking about a problem with OOP in general.

There is no other problem than people who suck as
programmers. Some of them learn to become better programmers,
others blame the programming language/paradigm.

Alf P. Steinbach

unread,
Nov 27, 2009, 4:18:47 PM11/27/09
to
* Howard Beale:

The above alleged quote of me is Howard's invention.


Cheers,

- Alf

Alf P. Steinbach

unread,
Nov 27, 2009, 4:24:47 PM11/27/09
to
* Pavel:

Incorrect.

Consider in class T construtor a call to a base class' foo which calls virtual
bar which is overridden in T.


> 2. It allows more efficient implementation (the known-to-me C++
> implementations first write a pointer to virtual table of the base class
> to the object; then override it with the pointer to derived class's
> table; this is unnecessary and unjustified overhead breaking the promise
> of C++ to be as efficient as possible)

Yes, efficiency can be improved.


> 3. The promise of C++ to be as powerful and dangerous to allow the
> programmer to blow up his/her entire leg is broken.

No, you can do whatever you want. But if you want to do nonsensical
initialization you'll have to do it yourself. Not via the language's mechanisms.


> 4. It is proven to work (by Java for example).

Meaningless unless you define "work". Java programs generally have problems here.

Pavel

unread,
Nov 28, 2009, 12:18:14 AM11/28/09
to
I am not sure I am following your sentence above. Did you mean this?

class BT { public:
void foo() { bar(); }
virtual void bar() { cout << "BT::bar()\n"; }
};

class T {
T() { foo(); }
};

This does not present a problem in either specs (existing or desired) as
the derived class' bar() is called in both cases. If you meant anything
different could you please show sample code?

>
>
>> 2. It allows more efficient implementation (the known-to-me C++
>> implementations first write a pointer to virtual table of the base
>> class to the object; then override it with the pointer to derived
>> class's table; this is unnecessary and unjustified overhead breaking
>> the promise of C++ to be as efficient as possible)
>
> Yes, efficiency can be improved.
>
>
>> 3. The promise of C++ to be as powerful and dangerous to allow the
>> programmer to blow up his/her entire leg is broken.
>
> No, you can do whatever you want.

Thanks! I guess I did not know that before.

> But if you want to do nonsensical
> initialization you'll have to do it yourself. Not via the language's
> mechanisms.

You can do whatever you want, too, in particular boldly business
requirements "nonsensical". Fortunately for both of us, I am not your
employer.

>
>
>> 4. It is proven to work (by Java for example).
>
> Meaningless unless you define "work". Java programs generally have
> problems here.

Fair enough. I define "Work" as "satisfy requirements" and "work well"
as "work at lesser cost than known alternatives". IMHO this aspect of
initialization (calling virtuals from constructors) works well in Java
and not so well in C++. Does it make more sense now?

Joshua Maurice

unread,
Nov 28, 2009, 1:53:59 AM11/28/09
to
On Nov 26, 10:19 pm, Howard Beale <n...@none.none> wrote:
> [1] As in the example I gave (and any example that could be given), you
> wouldn't know, by just looking at the code, that you're going to get the
> wrong output.  You would have to also know about the order in which
> constructors / destructors are called, which is exactly what is at issue
> here.  You may say that the output isn't "wrong," but I personally
> believe that if the area of a circle is pi*r^2 during its entire
> existence, then it's area should also be pi*r^2 when it is being created
> or destroyed.  And most programmers, unaware of this little gotcha,
> would say the same thing.  You, being a C++ proponent and expert, know
> differently, but most programmers prefer consistent behavior.  Yes, I'll
> grant that programmers also want safety, but it is entirely possible for
> a compiler to safely allow virtual methods during construction and
> destruction.

This sounds like the "wrong" position of the circle vs ellipse
problem. Just because in math "all circles are ellipses" does not mean
that "circle should be a subclass of ellipse". It doesn't matter if
the lack of inheritance will surprise "most programmers". In this
case, "most programmers" are wrong, and they will be making a bad
design decision if they went with it.

The writers of the standard, when they wrote the standard, decided to
try and make it difficult to shoot yourself in the foot. Generally,
when one shoots themself in the foot, it's by accident, and generally
by incompetence.

Put another way, "truth" is not democratic. Just because most
programmers think that a circle should "be an" ellipse does not make
it good code.

As another example, what about those programmers who find it
surprising that they can't access an object after it's deleted? Does
that mean manually memory management is bad and we should all be in a
garbage collected environment? Perhaps we should change POSIX as well
to support common anti-patterns, like double checked locking.

Virtual calls made in destructors and constructors do not go down to
the unconstructed most derived object because this would be a logical
error in nearly all cases. It seems as though you want such calls to
act on unconstructed objects, and in which case you are simply wrong,
as based upon years of evidence.

> [2] Do you know of a way to change the order in which constructors /
> destructors are called?  I don't, outside of writing a new compiler.

The order of construction of subobjects is designed as "syntactic
sugar". All of this you could do in C, but it would be a huge pain to
write out and maintain. Thus, the standard writers decided on the most
useful ordering. Frankly, it's quite a good ordering. They decided to
write a "syntactic sugar" which works really well for 99% of cases. If
you're really in that 1% of cases, you can still write out whatever
manually. However, I don't think you actually hit such a case, and are
instead complaining out of your ass that it doesn't do X when no one
actually needs X. (Where to be very clear, X is the order of
construction and destruction. Thus far, you haven't seemed to disagree
with this, just how virtual functions work in them.)

> [4] My compiler doesn't give me any warning when I call a virtual method
> from a constructor or destructor.  I don't know what more to tell you.

Yes. I agree that Quality of Implementation issues, like decent
warnings, is a huge problem with modern C++ implementations. (For
example, it annoys me to no end that I cannot find an option on \any\
compiler to flag deleting an incomplete type as a fatal error, or to
flag deleting a void pointer as a fatal error. Personally, I think
it's a shortcoming in the standard and implementations. Both errors
should require a diagnostic, and apart from a requirement from the
standard, any nonshitty compiler should have an option to flag both as
a fatal error turned on by default. I've spent days tracking down
problems from such things.)

Joshua Maurice

unread,
Nov 28, 2009, 2:09:43 AM11/28/09
to
After reading more, I'm still not quite clear on what Howard Beale
want, so I ask again. More clearly: what is wrong with C++, its order
of construction and destruction, and how virtual calls interact.

Let's first presuppose that constructors and destructors themselves
are not broken. Correct me if you think they are.

That leaves us with this heated, and quite unclear, discussion about
which function should be called when you call a virtual function in a
constructor or destructor. I think our options are:

1- Call function on uninitialized (or destroyed) derived class. This
will almost certainly be bad, and not what the programmer intended (or
the programmer is not familiar with the language and good code design,
and the design is bad).

2- What is currently done. It goes to the most derived currently
constructed object.

3- Disallow virtual function calls on objects under construction or
destruction.

I think I like #2 the most, though I can see some utility from #3.
Howard, I still think you are arguing for #1, and I strongly disagree
with that option on my knowledge and years of experience.

Alf P. Steinbach

unread,
Nov 28, 2009, 4:51:26 AM11/28/09
to
* Pavel:

class BT
{
private:
virtual void bar() { say( "BT" ); }
public:
void foo() { bar(); }
};

class T
: public BT
{
private:
virtual void bar() { say( "T" ); }
public:
T() { foo(); }
};

class D
: public T
{
private:
std::string myPavelonian;
virtual void bar() { say( myPavelonian.c_str(); }
public:
D(): myPavelonian( "D" ) {}
};

int main() { D(); }

Works well with C++ rules, calling T::bar as the T programmer intended.

Undefined behavior with Pavel/Howard rules.

Contrary to your claim there's no way to use explicit qualification in class T
or in class BT to make it call T::bar with Pavel/Howard rules.


>>> 2. It allows more efficient implementation (the known-to-me C++
>>> implementations first write a pointer to virtual table of the base
>>> class to the object; then override it with the pointer to derived
>>> class's table; this is unnecessary and unjustified overhead breaking
>>> the promise of C++ to be as efficient as possible)
>>
>> Yes, efficiency can be improved.
>>
>>
>>> 3. The promise of C++ to be as powerful and dangerous to allow the
>>> programmer to blow up his/her entire leg is broken.
>>
>> No, you can do whatever you want.
> Thanks! I guess I did not know that before.
>
>> But if you want to do nonsensical
>> initialization you'll have to do it yourself. Not via the language's
>> mechanisms.
> You can do whatever you want, too, in particular boldly business
> requirements "nonsensical".

Yes, it would be bold to require undefined behavior.


Hth.,

- Alf

Bo Persson

unread,
Nov 28, 2009, 6:44:54 AM11/28/09
to

You shouldn't always give people what they believe they want. :-)

Calling a virtual function on a non-existing object is one of those
things. Here C++ avoids undefined behavior by defining that you can
only call the function for the object that actually exists at that
point.

>
> 2. It allows more efficient implementation (the known-to-me C++
> implementations first write a pointer to virtual table of the base
> class to the object; then override it with the pointer to derived
> class's table; this is unnecessary and unjustified overhead
> breaking the promise of C++ to be as efficient as possible)

There is an extra cost for this, true.

>
> 3. The promise of C++ to be as powerful and dangerous to allow the
> programmer to blow up his/her entire leg is broken.

My impression is that C++ tries to avoid the shoot-in-the-foot
situation whenever possible (and without a run-time cost :-). This
does leave some opportunities for blowing a leg off, for the
adventurous programmer.

>
> 4. It is proven to work (by Java for example).

For some definition of work. I'm no Java expert, but from what I
understand the cost you want to avoid in 2) now moves to a test for a
fully constructed object in every call to the function.

>>
>> That is the responsiblity of the derived class' constructor, which
>> will no doubt be executed a microsecond later.
>>

My point is that the derived object should fully construct itself, and
not depend on the base object calling some function during its
construction. It is about the distribution of responsibilities.


Bo Persson


Bo Persson

unread,
Nov 28, 2009, 6:49:23 AM11/28/09
to

A agree with this, and believe that in the few cases where #1 might
actually work is where it just returns a fixed value to the caller. In
those rare cases, the value could just as well be a parameter to the
base class' constructor.


Bo Persson


Pavel

unread,
Nov 28, 2009, 2:12:22 PM11/28/09
to
T::T() { T::bar(); } /* "no way" puzzle solved in a one-liner; the
desired behavior achieved. BTW what was the purpose of foo() (other than
obscuring the question)? Reading or re-reading this
http://chalain.livejournal.com/39332.html may help you map requirements
to source code in a more straightforward way. */

BTW. If you believe your way of selecting variable names is funny, you
are fooling yourself. In me personally, it raises a doubt about a
possibility of impersonal technical conversation with you. I am not sure
know how much longer I will want to answer to posts obeying the like
"coding standard" or other personal references so don't get surprised or
too pleased by yourself for writing a smart post if you find it left
without a reply from me.

>>>> 2. It allows more efficient implementation (the known-to-me C++
>>>> implementations first write a pointer to virtual table of the base
>>>> class to the object; then override it with the pointer to derived
>>>> class's table; this is unnecessary and unjustified overhead breaking
>>>> the promise of C++ to be as efficient as possible)
>>>
>>> Yes, efficiency can be improved.
>>>
>>>
>>>> 3. The promise of C++ to be as powerful and dangerous to allow the
>>>> programmer to blow up his/her entire leg is broken.
>>>
>>> No, you can do whatever you want.
>> Thanks! I guess I did not know that before.
>>
>>> But if you want to do nonsensical
>>> initialization you'll have to do it yourself. Not via the language's
>>> mechanisms.
>> You can do whatever you want, too, in particular boldly business
>> requirements "nonsensical".
>
> Yes, it would be bold to require undefined behavior.

Business requirements are well defined. The behavior of my code above is
well defined under the current Standard. It would be well defined under
the more reasonable standard that Howard and myself would like to see,
too. Your code's behavior would be undefined under such a Standard. This
would be your code's issue. Under the current Standard, it is possible
to write a lot of code with undefined behavior. Everybody knows this and
C++ is not judged by how easy it is to write code with undefined
behavior. Everyone would agree it is very easy to do. C++ is judged by
how easy it is to write the code that solves a particular problem and
how easy it is to read and understand the code.

Try to make the following code (that means to track the creation of
objects of classes derived from Object and that would work under "our"
rules), work under the current Standard's rules. Try to fairly estimate
the difference in the cost/complexity of the resulting code:

void say(const char *msg) { cout << msg << '\n'; }

class Object {
public:
Object() { say(name()); }
virtual const char *name() {return "Object";}
};

class Foo : public Object {
public:
const char *name() { return "Foo"; }
};

class Bar : public Object {
public:
const char *name() { return "Bar"; }
};

int main() { Foo o; Bar o1; return 0; }

>
>
> Hth.,
>
> - Alf

Cheers,
-Pavel

Pavel

unread,
Nov 28, 2009, 3:29:25 PM11/28/09
to
Are we being completely honest here referring to the object as
"non-existing"? Under the current rules it does not exist but we are
discussing the quality of this very rules, aren't we? Under the proposed
(and time-tested) changed rules it would be existing, just not fully
initialized. Calling functions (virtual or not) on a
not-fully-initialized object is nothing new: a member function called
from the constructor is called on a not-fully-initialized object. What
is a point of discussing the conceptual correctness of letting people
call functions on a not-fully-initialized object when they already can
do it?

>> 3. The promise of C++ to be as powerful and dangerous to allow the
>> programmer to blow up his/her entire leg is broken.
>
> My impression is that C++ tries to avoid the shoot-in-the-foot

Not to avoid, but make it harder:
"In C++ it's harder to shoot yourself in the foot, but when you do, you
blow off your whole leg." � Bjarne Stroustrup.

It did not mean to make legitimate work harder, though. And the ability
to express useful ideas always comes at cost of danger. Remember
standard Pascal? It was clearly as safe as a language can get; so safe
that it was impossible to write anything useful in it (useful varieties
like Turbo Pascal introduced external modules, so they became useful but
lost the ability to statically proof the correctness). Certainly it is a
matter of personal choice where to draw the line and that's to try to
throw in some objectivity I refer to Java: From both my experience and
the prevalent opinion, Java is much safer language than C++ (and
respectively slightly less universal and capable). Therefore a litmus
test to me is: if something is safe enough for allowing it in Java, not
including that same capability in C++ for safety reasons is probably not
a good idea.

> situation whenever possible (and without a run-time cost :-). This
> does leave some opportunities for blowing a leg off, for the
> adventurous programmer.


>
>>
>> 4. It is proven to work (by Java for example).
>
> For some definition of work. I'm no Java expert, but from what I
> understand the cost you want to avoid in 2) now moves to a test for a
> fully constructed object in every call to the function.

Nah, it just lets you slip (Java!); see
http://en.wikipedia.org/wiki/Virtual_function#Java_2.

BTW, I just found the reference to this article of Scott Meyers ibid in
Wikipedia: http://www.artima.com/cppsource/nevercall.html. I think
logically those who agree with this his opinion should agree to us
(Howard and myself) as well: what a point in having a "safety feature"
that is recommended to be used .. never?

I say "logically" because Scott himself would apparently disagree:

"... That's how every part of C++ will treat it, and the treatment makes
sense: the BuyTransaction-specific parts of the object haven't been
initialized yet, so it's safest to treat them as if they didn't exist".

I, on the other hand, cannot see a big difference between calling any
function within a constructor (where some parts of an object may not
have been initialized yet) and calling a virtual function ibid. I
believe that treating the derived-class object as "non-existing" before
entering its construction function is an arbitrary and not very useful
choice of the Standard.

>
>>>
>>> That is the responsiblity of the derived class' constructor, which
>>> will no doubt be executed a microsecond later.
>>>
>
> My point is that the derived object should fully construct itself, and
> not depend on the base object calling some function during its
> construction. It is about the distribution of responsibilities.

See, if only purpose why constructors are used were the initialization
of the parts of the constructor's specific class I could agree to that.
In practice, however, there are other tasks that are hooked to the
constructors (because there is no other hooks in C++ for doing that in
general case). For example (the list is certainly incomplete):

1. To track creation of all objects in hierarchy where class-specific
information is necessary for tracking.
2. To complete the initialization of parallel bases.
3. To Register all created objects from hierarchy somewhere where the
registration data, registrar or registration algorithm is
derived-class-specific (that is, specific to static members of the
derived class or its state-independent behavior).

If C++ allowed an easy and inexpensive way of hooking in these (I am
aware of a wrapper/handler-based method but do not consider it easy
enough of inexpensive), a lion share of the current needs may have been
eliminated (I am not sure about all of them). As it is now, I see Java
behavior more beneficial.

-Pavel

>
>
> Bo Persson
>
>

Alf P. Steinbach

unread,
Nov 28, 2009, 3:38:45 PM11/28/09
to

Assume that foo performs an essential function.

Or, if one is meant to take your "solution" seriously, are you really advocating
wholesale duplication of code?

Jeez.


>Reading or re-reading this
> http://chalain.livejournal.com/39332.html may help you map requirements
> to source code in a more straightforward way. */

There was no requirement other than calling foo(), and any more
straightforwarding mapping than calling it is impossible.

So your comment is meaningless.

Or just trolling.


> BTW. If you believe your way of selecting variable names is funny, you
> are fooling yourself. In me personally, it raises a doubt about a
> possibility of impersonal technical conversation with you. I am not sure
> know how much longer I will want to answer to posts obeying the like
> "coding standard" or other personal references so don't get surprised or
> too pleased by yourself for writing a smart post if you find it left
> without a reply from me.

You're trolling.

I hope...

Paavo Helde

unread,
Nov 28, 2009, 6:21:24 PM11/28/09
to
Howard Beale <no...@none.none> wrote in news:Xns9CD072BE1CB51nonenonenone@
69.16.186.8:

> Balog Pal wrote:
>
>>> If you don't want that, fine.
>>
>> Life rarely considers what we want. :-o We have what we have. A
>> circle-under-counstruction is NOT a circle-complete. Same goes for
>> circle-being-destroyed. If it is drawn on paper, you can see the same
>> thing.
>
> Good point. We're talking about a problem with OOP in general. And
> maybe the answer is that OOP isn't "what we want." We're talking about
> defining a programming language -- made by us, made for us, so "what we
> want" really does matter in this case. You're basically saying "we
> invented C++ and it didn't pan out as well as we might have hoped, so
> we're stuck with it."
>
>
>> But really, what would be the alternative of construction? I observed
>> it as a fundamental approach. SICP suggests the same.
>
> There are plenty of languages (paradigms) that don't invlove
> constructors. C, which is where this discussion started, is a great
> example.
>
>
>> Ok, we all dislike it. Really. But what should be the alternative?
>> Which solution we would NOT dislike?
>
> Well, that's why we all come to usenet. To battle trolls and once in a
> blue moon, answer a worthwhile question like the one you just re-asked.

If I understood correctly, then your aim is to be able to call virtual
methods at construction and destruction time and expect them to wind up
in the most derived object, presumably assuming that those virtual
functions of the most derived object are careful enough to not touch
invalid data. This seems quite error-prone to me and I'm happy that such
behavior is not in the language by default. Maybe in some circumstances
it would be justified, but I'm not sure it would be supported by the core
language.

If it were supported, then such functions should be declared with an
additional keyword, maybe "static virtual" or whatever (though people
talking about static virtual functions usually want something else). In
any case, the implementation requires some extra data besides vtable
pointer in the base class object, as vtable pointer only cannot be used
for such behavior by the current language rules (as you have found out by
the hard way I guess). So I have sketched an example having an additional
member function pointer in the base class. To avoid undefined behavior,
the functions cannot have access to derived class B, as they are called
on an object which is not of type B at the moment. This rules out using
standard member functions, instead I'm using static member functions
here, to maintain an illusion of derivation. The "static virtual"
functions can call functions of the base class and other "static
virtual" functions (which would be technically also functions of the base
class).

#include <iostream>

class A;
typedef void (*func_t)(A&);


class A {
public:
A(func_t f=NULL): f_(f? f: &A::f) {
std::cout << "Entering A ctor body\n";
static_virtual_f();
std::cout << "Leaving A ctor\n";
}
virtual ~A() {
std::cout << "Entering A dtor body\n";
static_virtual_f();
std::cout << "Leaving A dtor\n";
}
void static_virtual_f() {
(*f_)(*this);
}
protected:
static void f(A& a) {
std::cout << "In A::f()\n";
}
private:
func_t f_;
};

class B: public A {
public:
B(func_t f=NULL): A(f? f: &B::f) {
std::cout << "Entering B ctor body\n";
static_virtual_f();
std::cout << "Leaving B ctor\n";
}
~B() {
std::cout << "Entering B dtor body\n";
static_virtual_f();
std::cout << "Leaving B dtor\n";
}
protected:
static void f(A& a) {
std::cout << "In B::f()\n";
}
};

int main() {

{
std::cout << "Creating A\n";
A a1;
std::cout << "Using A\n";
a1.static_virtual_f();
std::cout << "Deleting A\n";
}

std::cout << "\n";

{
std::cout << "Creating B\n";
B b1;
std::cout << "Using B\n";
b1.static_virtual_f();
std::cout << "Deleting B\n";
}
}

Output is:

Creating A
Entering A ctor body
In A::f()
Leaving A ctor
Using A
In A::f()
Deleting A
Entering A dtor body
In A::f()
Leaving A dtor

Creating B
Entering A ctor body
In B::f()
Leaving A ctor
Entering B ctor body
In B::f()
Leaving B ctor
Using B
In B::f()
Deleting B
Entering B dtor body
In B::f()
Leaving B dtor
Entering A dtor body
In B::f()
Leaving A dtor

Paavo Helde

unread,
Nov 28, 2009, 6:34:29 PM11/28/09
to
Joshua Maurice <joshua...@gmail.com> wrote in news:0695f935-8faf-40c0-
8828-069...@9g2000yqa.googlegroups.com:

> After reading more, I'm still not quite clear on what Howard Beale
> want, so I ask again. More clearly: what is wrong with C++, its order
> of construction and destruction, and how virtual calls interact.
>
> Let's first presuppose that constructors and destructors themselves
> are not broken. Correct me if you think they are.
>
> That leaves us with this heated, and quite unclear, discussion about
> which function should be called when you call a virtual function in a
> constructor or destructor. I think our options are:
>
> 1- Call function on uninitialized (or destroyed) derived class. This
> will almost certainly be bad, and not what the programmer intended (or
> the programmer is not familiar with the language and good code design,
> and the design is bad).

I think what he really wants is to define a function in derived class,
which can be called during construction and destruction of base class. As
such, this function cannot touch derived class data, neither call other
derived class functions which do this. This means that the function
effectively is a base class function, but defined in the derived class, and
presumably overrides some behavior of the base class function having the
samen name.

I just gave a C++ implementation example of such a function in another
post.


Regards
Paavo

Alf P. Steinbach

unread,
Nov 28, 2009, 6:50:27 PM11/28/09
to
* Paavo Helde:

Uhm, this issue is covered in the FAQ.

Howard Beale

unread,
Nov 28, 2009, 8:16:18 PM11/28/09
to
Joshua Maurice wrote:

> After reading more, I'm still not quite clear on what Howard Beale
> want, so I ask again. More clearly: what is wrong with C++, its order
> of construction and destruction, and how virtual calls interact.

I think it's pretty clear from his first handful of posts that Howard Beale
just doesn't care much for C++ or OOP in general.


> Let's first presuppose that constructors and destructors themselves
> are not broken. Correct me if you think they are.

Well, more explicit control might be nice. For example, have the compiler
only call the most-derived class's constructor/destructor and allow the
programmer to call bases classes' constructors/destructors if and when
needed, in whatever order is safe. Then any virtual methods involved in
the process could also safely resolve to the most-derived class. And it
would just be more consistent, in general, because then constructors and
destructors would work like any other virtual method: code in the base
classes is overridden (not executed) unless explicitly called or
duplicated.


> That leaves us with this heated, and quite unclear, discussion about
> which function should be called when you call a virtual function in a
> constructor or destructor.

That was actually just one of the issues named, and everyone latched onto
that, specifically. Probably because it's fairly commonly a topic of
discussion here.

Howard Beale

unread,
Nov 28, 2009, 8:23:16 PM11/28/09
to
Krice wrote:

> There is no other problem than people who suck as
> programmers. Some of them learn to become better programmers,
> others blame the programming language/paradigm.


Well, there you have it. Krice has settled the issue for us all. C++ is
perfect and if you complain about it you are an ugly, lame, retarded loser
with no life and no girlfriend and bad breath and skid marks in your
underwear. Thank you, Krice. Sorry that the rest of us are taking up
valuable space in your discussion group. I have just killfiled all users
in this group other than Krice, including myself, so that I can get right
down to the good stuff.

Joshua Maurice

unread,
Nov 29, 2009, 2:25:37 AM11/29/09
to
On Nov 28, 12:29 pm, Pavel

<pauldontspamt...@removeyourself.dontspam.yahoo> wrote:
> BTW, I just found the reference to this article of Scott Meyers ibid in
> Wikipedia:http://www.artima.com/cppsource/nevercall.html. I think
> logically those who agree with this his opinion should agree to us
> (Howard and myself) as well: what a point in having a "safety feature"
> that is recommended to be used .. never?
>
> I say "logically" because Scott himself would apparently disagree:
>
> "... That's how every part of C++ will treat it, and the treatment makes
> sense: the BuyTransaction-specific parts of the object haven't been
> initialized yet, so it's safest to treat them as if they didn't exist".
>
> I, on the other hand, cannot see a big difference between calling any
> function within a constructor (where some parts of an object may not
> have been initialized yet) and calling a virtual function ibid. I
> believe that treating the derived-class object as "non-existing" before
> entering its construction function is an arbitrary and not very useful
> choice of the Standard.

Simple example.

//
#include <string>

struct F
{
virtual std::string const& name() const =0;
};
struct G : F
{
std::string name_;
virtual std::string const& name() const { return name_; }
};
//

Now, if I wrote that sample correctly, let's look at F and G. Suppose
F's constructor calls name() for debugging purposes. If it were to go
to the most derived but not yet constructed object G, then it would
return a reference to the not yet construct string sub-object, and any
attempt to use it would probably crash because it's not initialized:
the internal pointer of std::string would point to garbage and
dereferencing it would crash or be equivalently bad. Moreover, if
instead of string you had an object with virtual functions, then
calling anything on it would be bad because it's virtual table has not
yet been set up, so calling any virtual function on the sub-object
would horribly fail.

To repeat your statement:

> I
> believe that treating the derived-class object as "non-existing" before
> entering its construction function is an arbitrary and not very useful
> choice of the Standard.

Generally speaking, calling any sort of member function on any
nontrivial class which has not been initialized will dereference an
uninitialized pointer or do some equally bad thing because of the
uninitialized data. That's the reasoning behind this decision by the
standard to make virtual calls not go to member functions of classes
which have not yet been initialized or started initialization. I would
claim that it's quite a rare class which it makes sense to call member
functions on it without basic initialization of the data. (Well,
unless that member function is a setter, aka that member function is
initialization.)

It's a very useful guarantee to know that in a constructor that all of
your sub-objects (base class sub-objects and member sub-objects) have
been constructed. It's part of the whole thrust of C++ to not (easily)
allow access to unconstructed or destroyed objects. Ex: The "new"
operator returns a fully constructed object, you can't access an
uninitialized object through virtual pointers, etc. The whole language
and standard are built around this idea. I like it. It works for 99%
of cases. I don't recall yet seeing a case which I would actually want
to define a different construction order, nor call functions on an
object which has not been initialized.

Joshua Maurice

unread,
Nov 29, 2009, 2:43:09 AM11/29/09
to
On Nov 28, 5:16 pm, Howard Beale <n...@none.none> wrote:
> Joshua Maurice wrote:
> > After reading more, I'm still not quite clear on what Howard Beale
> > want, so I ask again. More clearly: what is wrong with C++, its order
> > of construction and destruction, and how virtual calls interact.
>
> I think it's pretty clear from his first handful of posts that Howard Beale
> just doesn't care much for C++ or OOP in general.
>
> > Let's first presuppose that constructors and destructors themselves
> > are not broken. Correct me if you think they are.
>
> Well, more explicit control might be nice.  For example, have the compiler
> only call the most-derived class's constructor/destructor and allow the
> programmer to call bases classes' constructors/destructors if and when
> needed, in whatever order is safe.  Then any virtual methods involved in
> the process could also safely resolve to the most-derived class.  And it
> would just be more consistent, in general, because then constructors and
> destructors would work like any other virtual method: code in the base
> classes is overridden (not executed) unless explicitly called or
> duplicated.

At this point, I think your opinions are rather irrelevant because
you're attacking all of OOP, not just this one small aspect of C++.
You're saying that X sucks because of some inherent quality of X. In
other words, I now see this as not really an attack on constructor
destructor order. Any sane OOP requires this constructor destructor
order. You just dislike OOP in general.

I still think you're wrong, but at least you're not longer acting as
if blatantly trolling. Your arguments have been much more civil and
reasonable.

To reply to this specific point:

> For example, have the compiler
> only call the most-derived class's constructor/destructor and allow the
> programmer to call bases classes' constructors/destructors if and when
> needed, in whatever order is safe.

My succinct reply is that I find automatic calling of sub-object
constructors to be a very useful syntactic sugar which saves typing
time and bugs (from not having to remember to construct my base class
sub-objects). In my years of programming I have never once found
myself wishing "If only I could delay construction of a sub-object for
just a little longer", or at least when I have wanted that, I just
change the member sub-object into a pointer and new and delete the
former sub-object whenever I need. (Maybe in a really crazy embedded
system this might come up, but then I really wouldn't be using such
OOP idioms anyway as I'm under different fundamental constraints.)

> > That leaves us with this heated, and quite unclear, discussion about
> > which function should be called when you call a virtual function in a
> > constructor or destructor.
>
> That was actually just one of the issues named, and everyone latched onto
> that, specifically.  Probably because it's fairly commonly a topic of
> discussion here.

So, do you really want to allow calling functions on uninitialized or
de-initialized objects? Again, it breaks all of the standard idioms
and practices of C++, those which say you're only allowed to operate
on a "live" object. You rarely need to do anything else, and in those
rare situations, OOP isn't really what you'd be doing anyway, and you
can still do that other stuff in C++. C++ doesn't restrict you to
this, but it offers it to you. The best of both worlds for the
programmer who knows what he's doing.

Chris M. Thomasson

unread,
Nov 29, 2009, 4:26:21 AM11/29/09
to
"Joshua Maurice" <joshua...@gmail.com> wrote in message
news:9e1954a5-d231-493d...@c3g2000yqd.googlegroups.com...

> Simple example.

> //
> #include <string>


FWIW, I have seen this type of error quite a few times when I am looking at
thread wrapper's implemented as a base class. The base class run's the
thread from the damn constructor, which in turn calls a pure virtual
function to invoke the derived class thread entry point. This is a major
race-condition. If the thread runs and calls that virtual function BEFORE
the derived class is FULLY constructed, BOOOOM! You're dead!


Here is a quick example:
__________________________________________________________________
#include <sched.h>
#include <pthread.h>
#include <cstdio>


#define YIELD sched_yield(), sched_yield(), sched_yield


extern "C" void* thread_base_entry(void*);


class thread_base
{
pthread_t m_tid;
virtual void on_entry() = 0;
friend void* thread_base_entry(void*);


public:
thread_base()
{
pthread_create(&m_tid, NULL, thread_base_entry, this);
YIELD(); // LOL!
}


void join()
{
pthread_join(m_tid, NULL);
}
};


void* thread_base_entry(void* state)
{
thread_base& this_ = *static_cast<thread_base*>(state);
this_.on_entry();
return NULL;
}


class foo : public thread_base
{
void on_entry()
{
std::puts("Hello from foo!");
}


public:
foo()
{
std::puts("Hello from foo's CTOR!");
}
};


int
main()
{
{
foo f;

f.join();
}

return 0;
}
__________________________________________________________________

This will probably crash, then again it might not because the whole thing is
a giant race condition.

What a MESS!

:^o

[...]

Paavo Helde

unread,
Nov 29, 2009, 5:29:52 AM11/29/09
to
"Alf P. Steinbach" <al...@start.no> wrote in
news:hescsb$cvs$2...@news.eternal-september.org:

> * Paavo Helde:
...

>> I think what he really wants is to define a function in derived
>> class, which can be called during construction and destruction of
>> base class. As such, this function cannot touch derived class data,
>> neither call other derived class functions which do this. This means
>> that the function effectively is a base class function, but defined
>> in the derived class, and presumably overrides some behavior of the
>> base class function having the samen name.
>>
>> I just gave a C++ implementation example of such a function in
>> another post.
>
> Uhm, this issue is covered in the FAQ.

Then it is strange that we have a 100+ message thread here about a topic in
FAQ....

Yes, I found something similar indeed in the end of FAQ 23.6 (but not
exactly). However, this section is so long and complicated that I'm afraid
many readers will skip it. If an innocent one-line question deserves a 10-
page answer in the FAQ, then maybe OP was right in that some more language
support would be helpful.

Paavo

Paavo Helde

unread,
Nov 29, 2009, 5:51:26 AM11/29/09
to
Paavo Helde <myfir...@osa.pri.ee> wrote in
news:Xns9CD27F2CA...@216.196.109.131:

Ok, after reading some other OP responses I realize that he wants
something totally different - some kind of his own data structure, but
making use of C++ derivation syntax by unknown reasons. I'm afraid this
does not quite work out.

Regards
Paavo

Krice

unread,
Nov 29, 2009, 11:18:54 AM11/29/09
to
On 29 marras, 03:23, Howard Beale <n...@none.none> wrote:
> C++ is perfect and if you complain about it

You can complain about it until the end of days, but it
will not make you a better programmer. When you work with
language X it's obvious that you need to adapt to what the
creators of the language thought. If you can't do that,
try some other language. I have no difficulties with
C++, but then again I'm a genius, far superior than
average people.

Howard Beale

unread,
Nov 29, 2009, 5:48:00 PM11/29/09
to
Joshua Maurice wrote:

> At this point, I think your opinions are rather irrelevant because
> you're attacking all of OOP, not just this one small aspect of C++.
> You're saying that X sucks because of some inherent quality of X.

What? Why would that make an argument irrelevant? Getting-shot-in-the-
face sucks because of the inherent quality of getting-shot-in-the-face
that it makes you dead. If something sucks, it sucks. I'm not the
first person in the world to think OOP sucks, and the arguments made
here (against it) are really some of the least original.


> In other words, I now see this as not really an attack on constructor
> destructor order. Any sane OOP requires this constructor destructor
> order. You just dislike OOP in general.
>
> I still think you're wrong, but at least you're not longer acting as
> if blatantly trolling. Your arguments have been much more civil and
> reasonable.

Well fuck that. I won't let that happen again.


> To reply to this specific point:
>
>> For example, have the compiler
>> only call the most-derived class's constructor/destructor and allow
>> the programmer to call bases classes' constructors/destructors if and
>> when needed, in whatever order is safe.
>
> My succinct reply is that I find automatic calling of sub-object
> constructors to be a very useful syntactic sugar which saves typing
> time and bugs (from not having to remember to construct my base class
> sub-objects).

It doesn't save much typing. And it encourages just as many bugs as it
prevents, probably more. And it's inconsistent -- with any other
virtual method, the programmer must choose to call the base class
version if he wants it to be executed, but constructors and destructors
get this special treatment.


> In my years of programming I have never once found
> myself wishing "If only I could delay construction of a sub-object for
> just a little longer"

Yeah, I find it annoying far more often in destructors than in
constructors.


> So, do you really want to allow calling functions on uninitialized or
> de-initialized objects? Again, it breaks all of the standard idioms
> and practices of C++, those which say you're only allowed to operate
> on a "live" object.

Yes, because that's the spirit of C++. If the programmer wants to shoot
himself in the foot, then he should be allowed.

For example, I remember running into the oh-so-popular "OnInitDialog"
bug. For anyone who hasn't seen it before, it's a textbook example of
the behavior we're talking about. The function OnInitDialog() is a
method in the MFC's CDialog class. You're expected to override the
function and initialize your own dialog's controls there. And just
about everyone runs into this weird assertion that looks something like
this:

ASSERT(::IsWindow(m_hWnd))

I mean seriously, EVERY SINGLE newbie EVER hits this bug on their first
foray into MFC. The reason for the assertion is that you've done this:

BOOL MyDialogClass::OnInitDialog()
{
my_control_1.do_something();
my_contril_2.set_something("string");

return CDialog::OnInitDialog();
}

You need to call the base class version *before* doing anything with the
controls. But you're free to do other things (setup data structures, or
whatever) before. That's the nature of the beast. You need to
understand what the base class does before you go deriving your own
class from it. Constructors and destructors don't need to be any
different. Hitting an ASSERT() is good if it encourages the newbie to
understand what the code he's using is actually doing.

Howard Beale

unread,
Nov 29, 2009, 6:06:03 PM11/29/09
to
Krice wrote:

> try some other language. I have no difficulties with
> C++, but then again I'm a genius, far superior than
> average people.

I already know this well. I could tell instantly from the eloquence of
your posts that you are "far superior than average people." You are
preaching to the choir, my man. I also suspect that you ARE one of the
creators of C++, and probably many other languages. I have brought great
shame to myself and my entire family by speaking out against C++. But in
my defense, I did so only before I knew that YOU were the primary driving
force behind its creation. Please be merciful in your judgement of me.

Balog Pal

unread,
Nov 29, 2009, 9:49:37 PM11/29/09
to

"Howard Beale"

> For example, I remember running into the oh-so-popular "OnInitDialog"
> bug. For anyone who hasn't seen it before, it's a textbook example of
> the behavior we're talking about. The function OnInitDialog() is a
> method in the MFC's CDialog class. You're expected to override the
> function and initialize your own dialog's controls there. And just
> about everyone runs into this weird assertion that looks something like
> this:
>
> ASSERT(::IsWindow(m_hWnd))
>
> I mean seriously, EVERY SINGLE newbie EVER hits this bug on their first
> foray into MFC. The reason for the assertion is that you've done this:

Ah, more lies. I was a newbie, I used MFC (a lot), never had a problem
wioth that.

Maybe I read the MFC dox? Maybe I used it as intended by creators: click the
message to create the handler -- then put my code where it said

//TODO: insert your code here

? That was certainly *after* the call of the original?

> BOOL MyDialogClass::OnInitDialog()
> {
> my_control_1.do_something();
> my_contril_2.set_something("string");
>
> return CDialog::OnInitDialog();
> }

Quite obviously your control objects are bound wo UI objects in that last
call. MFC uses two-phase setup for many things.

Guess saying

CFile file;
file.Read(....);

is as surprizing -- who woud think to Open the frelling file? By either
calling Open, or using the ctor version that does that.

Or newbie is defined as 'I never RTFM, and have the right to troll if
something will not work as I just hack around random code'?

> You need to call the base class version *before* doing anything with the
> controls.

More precisely, you have to Attach() or use some similar 2nd phase init call
on your controls, directly or indirectly. And in general, have a clue about
both windows and the framework to do anything sensible. If so, work can be
done -- and having the bonus of hitting sensible asserts in *debug* builds
is good, when you do some clear nonsense.

Dereference a NULL pointer or sending message to a unknown window qualifies
fine.

> But you're free to do other things (setup data structures, or
> whatever) before. That's the nature of the beast. You need to
> understand what the base class does before you go deriving your own
> class from it. Constructors and destructors don't need to be any
> different.

And they aren't. Actually nothing fobids an implementation to add turn the
language into a kindergarten, and generate code with asserts on a whim...
Or generate warnings like that.

The mentioned VC does it too -- using this in the member init list triggers
a warning. One that would make sense to those trying to use it right away,
and annoying to those who just store it for later. Same could be done for
any other use case, maybe it would make the build time explode, or annoy
more users who actuallt did RTFM and know what they do -- or just use other
more straightforward means to detect traps as testing. TANSTAAFL. Decision
to just leave it can be is as reasonable, or more so.

There are open source compilers, you can do it yourself, or convince other
developers how cool your way would be -- real life compilers come with cool
extensions.

Sure actual work is hard, while whining is cheap.


Christopher Dearlove

unread,
Nov 30, 2009, 7:11:35 AM11/30/09
to
"Pavel" <pauldont...@removeyourself.dontspam.yahoo> wrote in message
news:008d46ef$0$23362$c3e...@news.astraweb.com...

> void say(const char *msg) { cout << msg << '\n'; }
>
> class Object {
> public:
> Object() { say(name()); }
> virtual const char *name() {return "Object";}
> };
>
> class Foo : public Object {
> public:
> const char *name() { return "Foo"; }
> };
>
> class Bar : public Object {
> public:
> const char *name() { return "Bar"; }
> };
>
> int main() { Foo o; Bar o1; return 0; }

class Object
{
public:
explicit Object(const char * name) { say(name); }
};

class Foo : public Object
{
public:

Foo() : Object("Foo") {}
};

class Bar : public Object
{
public:

Bar() : Object("Bar") {}
};

or if you prefer

class Foo : public Object
{
public:

Foo() : Object(name()) {}
static const char * name() { return "Foo"; }
};


Christopher Dearlove

unread,
Nov 30, 2009, 7:28:21 AM11/30/09
to
"Christopher Dearlove" <chris.d...@baesystems.com> wrote in message
news:4b13b64c$1...@glkas0286.greenlnk.net...

Following myself up, or if you really want to:

typedef const char * (* Name)();

class Object
{
public:
explicit Object(Name name) { say(name()); }
};

class Foo : public Object
{
public:

Foo() : Object(name) {}

Howard Beale

unread,
Nov 30, 2009, 3:52:15 PM11/30/09
to
Balog Pal wrote:

>> I mean seriously, EVERY SINGLE newbie EVER hits this bug on their
>> first foray into MFC. The reason for the assertion is that you've
>> done this:
>
> Ah, more lies. I was a newbie, I used MFC (a lot), never had a
> problem wioth that.

Well, that's because you (and Krice) are "a genius, far superior than
average people."


> Maybe I read the MFC dox? Maybe I used it as intended by creators:
> click the message to create the handler -- then put my code where
> it said
>
> //TODO: insert your code here
>
> ? That was certainly *after* the call of the original?

I'm sure it was, but most of us probably removed that comment once we
inserted some code. From there, it was fairly easy to forget when
changing the code later. But, like I said, you are clearly more evolved
and would not have such a problem, even when you were a newbie.

More importantly, I clearly wasn't complaining about the behavior of
OnInitDialog(). I was using it as an example to point out the
difference in the way that "regular" virtual methods behave, compared to
the way that constructors and destructors behave. If constructors and
destructors weren't chained, and it was up to the programmer to call the
base class versions, you'd see newbies running into the same issue as
they do in OnInitDialog(). My point was that it would be acceptable
because they ALREADY run into that behavior everywhere else. And this
entire discussion that we're having now -- which is apparently common
enough that it warrants a FAQ -- would be unnecessary.


>> Constructors and destructors don't need to be any different.
>
> And they aren't.

They aren't? Then I guess this whole discussion was based on a false
premise. I was under the impression that constructors and destructors,
unlike other virtual methods, were automatically "chained" for you by
the compiler. Apparently other posters in this thread were under the
same impression.


> Actually nothing fobids an implementation to add turn the language
> into a kindergarten, and generate code with asserts on a whim... Or
> generate warnings like that.

I have no idea what this sentence means.


> Sure actual work is hard, while whining is cheap.

I like to think that I take whining to a new level. Whining with my
astounding level of insight is actually quite hard. You seem to be
under the impression that I'm looking for a solution to this one little
issue with the "virtual" keyword. It was just one of a bunch of
complaints about C++. I can't really control which issues the rest of
comp.lang.c++ chooses to discuss -- this one just happened to be
popular.

As I've said elsewhere in this thread, I do have a solution to the
problem, as well as the other issues that weren't even addressed here.
So, it's fair to say that I've done equal parts "actual work" and
"whining." I am fine with that. I'm allowed to point out what I
dislike about C++, or OOP, regardless of whether or not I have a working
alternative.

Joshua Maurice

unread,
Nov 30, 2009, 5:27:06 PM11/30/09
to
On Nov 29, 2:48 pm, Howard Beale <n...@none.none> wrote:
> Joshua Maurice wrote:
> > At this point, I think your opinions are rather irrelevant because
> > you're attacking all of OOP, not just this one small aspect of C++.
> > You're saying that X sucks because of some inherent quality of X.
>
> What?  Why would that make an argument irrelevant?  Getting-shot-in-the-
> face sucks because of the inherent quality of getting-shot-in-the-face
> that it makes you dead.  If something sucks, it sucks.  I'm not the
> first person in the world to think OOP sucks, and the arguments made
> here (against it) are really some of the least original.

Let me use an analogy. Suppose you go to a circus and declare that you
don't like the clown's hats. In actuality, you just don't like any
kind of clown, but their hats is one of your reasons, but not your
only reason, for not liking clowns. if your actual and only problem
was with the clown's hats, then maybe the owner would change their
hats for you. However, the owner will not care about your hat problem
as soon as he learns that you hate all kinds of clowns.

To go back from analogy. I might care more about your complaints on
constructor destructor order, and virtual calls going to the currently
constructed object vs not-constructed most-derived, if you actually
used objects at all. Even if I changed these things, presumably you
still wouldn't use them.

Balog Pal

unread,
Nov 30, 2009, 5:42:49 PM11/30/09
to
"Howard Beale" <no...@none.none>

>>> Constructors and destructors don't need to be any different.
>>
>> And they aren't.
>
> They aren't? Then I guess this whole discussion was based on a false
> premise. I was under the impression that constructors and destructors,
> unlike other virtual methods, were automatically "chained" for you by
> the compiler. Apparently other posters in this thread were under the
> same impression.
>
>
>> Actually nothing fobids an implementation to add turn the language
>> into a kindergarten, and generate code with asserts on a whim... Or
>> generate warnings like that.
>
> I have no idea what this sentence means.

From the original it seemed your problem is that there are no ASSERTs
provided when the ctor/dtor case is messed up.

Turns out it is chaining. Sure, there is a difference. But for a very good
reason. ctors/dtors must chain for correctness. In proper order too.

Normal virtuals can just replace the original entirely (and the original may
not even exist, unlike!). Or may call the original. As first tging, or the
last thing, or in the middle.

>> Sure actual work is hard, while whining is cheap.
>
> I like to think that I take whining to a new level. Whining with my
> astounding level of insight is actually quite hard. You seem to be
> under the impression that I'm looking for a solution to this one little
> issue with the "virtual" keyword.

No, at your original post it looked like mindless trolling, I was only
dragged in by Alf's unfortunate claims.

After discussion it looks less trolling, but that you have pretty little
understanding of what's going on and why. But build an even stronger
opinion. I'd suggest read books like Design & Evolution of C++. Or Matthew
Wilson's Imperfect C++.

Guess if you did that with open mind, afterwards reading your own post would
just say OMG.

> As I've said elsewhere in this thread, I do have a solution to the
> problem, as well as the other issues that weren't even addressed here.

A solution that needs change of language, or one that accepts it in current
form, and is like a workaround?

For the first kind you're in the wrong place -- comp.std.c++ is ways better,
and you could have simply start with pointing to the proposals you
submitted, or put down your draft to discuss. It would probably drawn
some positive interest even if we know well that there is a feature-close
mode.

For the second, again, you could have started with the solution, if you
actually have them -- as the "problems" hardly worth a yawn, those who
work with the language did find workarounds for mush more realistic
things, or read about them in really elaborate books like just mentioned
Wilson's.

> So, it's fair to say that I've done equal parts "actual work" and
> "whining." I am fine with that.
> I'm allowed to point out what I
> dislike about C++, or OOP, regardless of whether or not I have a working
> alternative.

You know the "law of assholes": everyone have one, and dont much care about
someone other's... Same goes for opinions.

I for example don;t like java, but never had the urge to go to a java forum
and start saying how much it sucks. Can find better things to spend time
on.

Howard Beale

unread,
Nov 30, 2009, 6:31:34 PM11/30/09
to
Balog Pal wrote:

>> As I've said elsewhere in this thread, I do have a solution to the
>> problem, as well as the other issues that weren't even addressed
>> here.
>
> A solution that needs change of language, or one that accepts it in
> current form, and is like a workaround?

A solution that circumvents C++ entirely. In fact, it's so far from C++
that it's really not even appropriate to discuss here. However, it still
provides all the benefits of C++ (or any other OOP language), as well as a
few more perks that they don't offer. It is built on top of C, mostly.
The only reason I chose to attack C++ is that, despite how much I dislike
it, it really is currently the best choice that there is. One of the very
first posts in this thread summed it up nicely:

"C++ is bad. It's just that all of the reasonable alternatives
are worse." - James Kanze

I really expected the responses to be more along the lines of "Fuck off,
troll, C++ rules." If the religiously fanatical defenders of C++ aren't
lurking in this group, I don't know where they are...


> You know the "law of assholes": everyone have one, and dont much care
> about someone other's... Same goes for opinions.
>
> I for example don;t like java, but never had the urge to go to a java
> forum and start saying how much it sucks. Can find better things to
> spend time on.

Hot damn, that is seriously a really good point. Maybe the best point in
this entire thread. I didn't expect to spawn such a huge discussion -- I
actually assumed that criticism of C++ was common enough that no one would
really even notice. I don't know, sometimes it's just fun to pick on an
easy target. The intense blowback that I got actually made me start to
think, "Hey, maybe there's really something to this."

0 new messages