Author Topic: Building C::B with GCC 4.1.0  (Read 20730 times)

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: Building C::B with GCC 4.1.0
« Reply #15 on: February 09, 2006, 09:07:46 pm »
I also got this advice from a C++ expert:
Quote
If your constructor does nothing: better not to define it. You can define a dummy destructor - but if you do it, define it as virtual.
This is actually quite a bad advice in my opinion. An empty constructor does not help, but it does not harm either.

On the other hand, a virtual destructor does harm. Maybe "harm" is the wrong word, let's say "cost", but the general idea is the same. At the very least, this bears an unnecessary storage cost of one pointer in the vtable plus one pointer for every allocated object. The single vtable entry may be neglegible, but if you allocate and deallocate 5 million objects, then carrying around one unnecessary v-ptr for each object may make a difference (as may the two additional pointer dereferences to call a destructor that does nothing...).
As always, the significance depends on what you do, but I think carrying around a penalty that you absolutely don't need is not a good idea.
You could say it is like using x++; or ++x;, the difference (if any) is not terribly big... but then, here we do bother ;)

The one and only case in which you really need a virtual destructor is when all of the following three conditions are met:
1. you have one or more virtual functions
2. you allocate an object of a derived class
3. you free this object as a type of the base class

For convenience, and for safety, one usually defines a virtual class' destructor virtual, as it does not make much difference (you have to carry the v-ptr around anyway) and you don't have to worry about who might derive from and tamper with your class.
However, it makes no sense at all to make a destructor virtual in a non-virtual class just for the sake of doing it.

Thank you very much for your explanation about virtual destructor :). What you say is correct. It is also what all the C++ websites I have looked at say. Anyway, I think that I have probably not correctly understood the advice of that person, who IMHO is a C++ expert (he is involved in the C++ Standardization Process and I would be very surprised if he had gave me an uncorrect advice). I will ask him and post here his answer.

Sorry for the not so accurate advice :oops: and thank you Thomas for pointing that out :D.

Michael

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
Re: Building C::B with GCC 4.1.0
« Reply #16 on: February 09, 2006, 09:26:59 pm »
Anyway, I think that I have probably not correctly understood the advice of that person, who IMHO is a C++ expert
Maybe he said "if you add a dummy destructor to a virtual class, make it virtual"?
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: Building C::B with GCC 4.1.0
« Reply #17 on: February 09, 2006, 09:50:37 pm »
Anyway, I think that I have probably not correctly understood the advice of that person, who IMHO is a C++ expert
Maybe he said "if you add a dummy destructor to a virtual class, make it virtual"?

No. I have just copied and past his remark.

I have implemented a template PriorityQueue class, which made use of a multimap. But I did not derived my class from the STL multimap. My class was more a wrapper.

My constructor and destructor originally were defined as:

Code
template
<
typename A,
typename P,
typename Cmp=greater<P>
>
class PriorityQueue
{
public:
/*Default constructor*/
PriorityQueue(void);

/*Destructor*/
~PriorityQueue(void);
...
};


/*
Default constructor
*/
template
<
typename A,
typename P,
typename Cmp
>
PriorityQueue< A, P, Cmp >::PriorityQueue()
{
}

/*
Destructor
*/
template
<
typename A,
typename P,
typename Cmp
>
PriorityQueue< A, P, Cmp >::~PriorityQueue(void)
{
}
...

When I asked him what he thought about my class he answered me:

Quote
Minor remarks:

1. In the constructor and destructor:
   PriorityQueue(void)
   In C++ you dont need to write f(void), f() is the same.

2. If your constructor does nothing: better not to define it.
   You can define a dummy destructor - but if you do it,
   define it as virtual.

May be I have misunderstand something. Anyway, his explanation was not too much detailed.

Michael

[EDIT]: I can post my class, if you would like to look at it.
« Last Edit: February 09, 2006, 09:55:30 pm by Michael »

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
Re: Building C::B with GCC 4.1.0
« Reply #18 on: February 09, 2006, 10:07:39 pm »
I don't get the point with the virtual destructor, to me it seems wrong. But hey, don't bother, I am neither God nor Stroustrup, so I would not know :)

In C++ you dont need to write f(void), f() is the same.
Isn't that the infamous construct that Stroustrup called an abomination? :lol:
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: Building C::B with GCC 4.1.0
« Reply #19 on: February 09, 2006, 10:15:46 pm »
In C++ you dont need to write f(void), f() is the same.
Isn't that the infamous construct that Stroustrup called an abomination? :lol:

Stroustrup calls it an abomination, but Dennis and Doug too: :D:

Quote
Bjarne Stroustrup said this in an interview with Dr. Dobbs Journal:

Dennis Ritchie and Doug McIlroy famously gave me courage to break with
ANSI C in the issue of the declaration of a function with an empty
argument list. To preserve compatibility with K&R C, I had invented the

int f(void);

notation for C with Classes. Initially, I retained the old meaning of

int f();

as "f()" can accept any arguments that happens to be compatible with
f()'s (unseen) definition". Dennis and Doug called the f(void) style
declaration an abomination, so in C++

int f();

now has the obviuos meaning: "f() takes no arguments." Unfortunately,
ANSI C adopted f(void) so I had to introduce f(void) into C++ for ANSI C
compatibility.

Na ja, f() or f(void)... :D

Michael
« Last Edit: February 09, 2006, 10:19:05 pm by Michael »

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: Building C::B with GCC 4.1.0
« Reply #20 on: February 10, 2006, 11:28:35 am »
I don't get the point with the virtual destructor, to me it seems wrong. But hey, don't bother, I am neither God nor Stroustrup, so I would not know :)

It seems that I have misunderstood the remark of the expert :). His explanation was may be a bit too short :roll:. After asking him again he told me:

Quote
If you have a pure class, which has no virtual function, and you will likely _not_ to derive from this class: there is no reason to define a virtual destructor. You may still define a non-virtual destructor if you have to do some clean-up on the end of the object lifetime.

However if you create a class which is part of a class hierarchy, and you intend to derive other classes from this class, and even more if you plan to use this hierarchy in polymorphic way (i.e. calling virtual functions, etc...) it is a good design choice to create a virtual destructor, even if you have nothing to clean-up in the base class.

This seems to confirm what you have said.

Michael

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
Re: Building C::B with GCC 4.1.0
« Reply #21 on: February 14, 2006, 04:34:03 pm »
Allow me to come back to this off-topic one last time :lol:

Apparently, this virtual destructor thing is a wide-spread misconception because I encountered a couple of people in the past few days who told me the exact same thing ("yea, it's a good thing, I always do it..."). The last one only a few minutes ago.

Thus, to visualize how expensive unnecessary virtual functions can be, I wrote the following code:
Code
#include <stdio.h>

class Integer {int a;};

class VirtualFoo{public: virtual ~VirtualFoo(){};};

class VirtualInteger
{
    int a;
public:
    virtual void Empty(){};
};

class MultiVirtualInteger: public VirtualFoo, public VirtualInteger {};

int main()
{
    int a;
    Integer b;
    VirtualInteger c;
    MultiVirtualInteger ow;
    Integer d[50000];
    Integer e[50000];
    VirtualInteger f[50000];
    MultiVirtualInteger this_hurts[50000];

    printf("int:\t\t\t %d\n", sizeof(a));
    printf("Integer:\t\t %d\n", sizeof(b));
    printf("VirtualInteger:\t\t %d\n", sizeof(c));
    printf("MultiVirtualInteger:\t %d\n\n", sizeof(ow));
    printf("int[]:\t\t\t %d\n", sizeof(d));
    printf("Integer[]:\t\t %d\n", sizeof(e));
    printf("VirtualInteger[]:\t %d\n", sizeof(f));
    printf("MultiVirtualInteger[]:\t %d\n", sizeof(this_hurts));

    return 0;
}
Please excuse the C/C++ mixture, I will probably never learn to use streams :P

The program outputs the following on a "typical" 32 bit machine:
Code
int:                     4
Integer:                 4
VirtualInteger:          8
MultiVirtualInteger:     12

int[]:                   200000
Integer[]:               200000
VirtualInteger[]:        400000
MultiVirtualInteger[]:   600000

Press any key to continue.
As can be seen, it costs nothing to encapsulate an integer into a class (I left out accessors, so it is not really useful, but let's not be picky). Contrarily, having virtual functions (even if it's just the empty destructor) costs one extra pointer per object (and per virtual inheritance). On a 64bit system, the overhead would of course be twice as much.

So, what do we learn from this? Virtual functions are evil, don't use them? No, surely not. Virtual functions are good and useful. But we should know that they are not free (especially not in combination with multiple inheritance, as shown).
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."

Offline killerbot

  • Administrator
  • Lives here!
  • *****
  • Posts: 5504
Re: Building C::B with GCC 4.1.0
« Reply #22 on: February 14, 2006, 04:48:44 pm »
what brings us to the topic, that way to many people overutilize multiple inheritance.
Try to avoid it as much as possible. You should only inherit from interfaces (abstract classes), occassionaly you need to inherit from more then 1 interface, but normally you shouldn't (rethink your design) .
Too many people use inheritance to reuse implementation, it should be used for behaviour (!! : IS A relation ship). Most implementation reuse can be done through aggregation.

Typical example :
Shape, Circle, Square, Rectangle :
Shape : base
Derived from shape : Circle, Square and Rectangle

Square is not dereived from rectangle !!!! Square can be implemented by having inside a Rectangle member.

Say you have the method : SetWidth()/SetHeight() and it's Get equivalents. Basic expectations is, they get/set what they say. For a rectangle you will not expect that SetWidth() would change the height !! But for a square setting one, also changes the other. So a square does not behave like a rectangle --> IS NOT A --> so no inheritance, but you can easlity implement a square on the inside by using a rectangle (eg : Square :SetHeight -> on the rectangle inside set height and width).

Note that many textbooks have been using this as an example, and have shown it WRONG !!!
Mathimatically a square is a rectangle ,but not in behaviour. And behaviour is interfaces, and interfaces are subject for inheritance.

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: Building C::B with GCC 4.1.0
« Reply #23 on: February 14, 2006, 07:23:13 pm »
@Thomas

Your demostration is very interesting. Personally, I have always appreciated C++ multiple-inheritance (especially when programming with Java :D). Anyway, it has a cost as you correctly demonstrate. I just wonder if C++ Class Flattening could be used to reduce the overhead due to the virtual functions...

I am curious to know what all the books written by C++ Experts that I have bought, will say about it :D.

@Killerbot

As told above I like multiple-inheritance, but not wild inheritance. I just not use multiple-inheritance, because it exists. But I like that it is there in case of need. With Java it was different and I quite never felt comfortable with the interfaces and single inheritance.

Your examlple is also interesting and helpful.

The design of an application is a very important point and always underestimated. At the beginning, I just wanted to code and not waste my time with the design. Later, I had to change most of my code, because of errors and inefficiency. Now, I take more time to design my application in order to avoid problems later (but I still prefer to code :D).

Michael

Offline killerbot

  • Administrator
  • Lives here!
  • *****
  • Posts: 5504
Re: Building C::B with GCC 4.1.0
« Reply #24 on: February 14, 2006, 08:17:15 pm »
Quote
I am curious to know what all the books written by C++ Experts that I have bought, will say about it

Check out Scot Meyers and Herb Sutters their books ...

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: Building C::B with GCC 4.1.0
« Reply #25 on: February 14, 2006, 08:22:18 pm »
Quote
I am curious to know what all the books written by C++ Experts that I have bought, will say about it
Check out Scot Meyers and Herb Sutters their books ...

Unfortunately, I do not have those books :(.

Michael

Offline thomas

  • Administrator
  • Lives here!
  • *****
  • Posts: 3979
Re: Building C::B with GCC 4.1.0
« Reply #26 on: February 14, 2006, 08:24:30 pm »
Quote
I have always appreciated C++ multiple-inheritance (especially when programming with Java Very Happy). Anyway, it has a cost as you correctly demonstrate.
Multiple inheritance is really no bad thing, that's not what I wanted to demonstrate :lol:
My point was that multiple virtual inheritance is still more expensive than (single) virtual inheritance.

In fact, I believe that multiple inheritance is one of the best features of C++, you only have to keep a few things in your head. One such thing is the "Diamond of Dread", and another example is the extra memory cost for virtual base classes.

Let's not forget that neither Stroustrup is stupid, nor are the ISO committee members, so if multiple inheritance was really that bad, then it wouldn't have been implemented in the first place, and it would never have made it into the standard ;)

Java has no multiple inheritance mainly for three reasons:
1. A compiler (and a virtual machine) supporting multiple inheritance is harder to implement and requires more resources.
2. C++ was designed to write software that runs country-wide call-centers, international airports, and airline booking systems. Java was designed to run embedded smart appliances ( = toasters with internet access).
3. Multiple inheritance (C++ in general) is not fool-proof. You really have to know what you do, and you really have to think about what you do, or your life will be a very unhappy one. Java, however, was explicitely designed for fools. Java does not require the programmer to think about "dangerous" things (in fact, it does not even allow it). The good side (and certainly one reason why Java was so successful) is that this avoids many problems alltogether.
"We should forget about small efficiencies, say about 97% of the time: Premature quotation is the root of public humiliation."

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: Building C::B with GCC 4.1.0
« Reply #27 on: February 14, 2006, 08:49:16 pm »
Quote
I have always appreciated C++ multiple-inheritance (especially when programming with Java Very Happy). Anyway, it has a cost as you correctly demonstrate.
Multiple inheritance is really no bad thing, that's not what I wanted to demonstrate :lol:
My point was that multiple virtual inheritance is still more expensive than (single) virtual inheritance.

In fact, I believe that multiple inheritance is one of the best features of C++, you only have to keep a few things in your head. One such thing is the "Diamond of Dread", and another example is the extra memory cost for virtual base classes.

Let's not forget that neither Stroustrup is stupid, nor are the ISO committee members, so if multiple inheritance was really that bad, then it wouldn't have been implemented in the first place, and it would never have made it into the standard ;)

Yes, I agree. If it was such an evil thing Stroustrup and the ISO C++ committee members would have never implemented it.

2. C++ was designed to write software that runs country-wide call-centers, international airports, and airline booking systems. Java was designed to run embedded smart appliances ( = toasters with internet access).

Well, toasters with internet access are especially useful for housewifes, or :D? So, they can prepare a tost while writing an email, speaking with a friend or watching the latest telenovela :).

To be serious, Java seems also to be useful to develop Web Services and related applications.

3. Multiple inheritance (C++ in general) is not fool-proof. You really have to know what you do, and you really have to think about what you do, or your life will be a very unhappy one. Java, however, was explicitely designed for fools. Java does not require the programmer to think about "dangerous" things (in fact, it does not even allow it). The good side (and certainly one reason why Java was so successful) is that this avoids many problems alltogether.

Yes, you are right about Java. Anyway, it is not easy in Java to develop efficient software.

Personally, I prefer a language as C++. May be more difficult to learn and master, but more powerful and flexible. I also wait to see what D will become.

Michael

Offline Michael

  • Lives here!
  • ****
  • Posts: 1608
Re: Building C::B with GCC 4.1.0
« Reply #28 on: April 25, 2006, 02:55:42 pm »
Quote
You'ren't missing anything really. I just named the problem, why and where it happened, but the only interest shown there was how I got to compile GCC 4.1.0 Smile
And I still have not managed to compile it... :(

I am not sure, but may be this post could help you to compile GCC 4.1.

Best wishes,
Michael