POV-Ray : Newsgroups : povray.unix : C++ problem Server Time
31 Oct 2024 14:11:10 EDT (-0400)
  C++ problem (Message 1 to 10 of 13)  
Goto Latest 10 Messages Next 3 Messages >>>
From: Peter Popov
Subject: C++ problem
Date: 28 Jul 2001 10:18:07
Message: <66b5mtg5prajt3ebi52l7imlgmm9tdhnra@4ax.com>
I am crossposting this to .programming and .unix because I don't
really know the source of the problem - my incompetence with C++ or my
compiler (gcc).

This isn't really POV-related ATM but will be at some point in time.
Anyway...

I am developing a set of classes for vector operations. Every class is
separated in a separate pair of .hh and .cc files.

The problem occurs when trying to include header file A in B and B in
A. For example,

// $Id: cvector.hh,v 1.6 2001/07/27 13:20:39 peter Exp $

#ifndef CVECTOR_HH_
#define CVECTOR_HH_ 

#include "ctransf.hh"

class CVector {
   ... // snipped some stuff to save space
   void Transform (const CTransform &);
};

#endif

// $Log: cvector.hh,v $
// Revision 1.6

and then I have this file:

// $Id: ctransf.hh,v 1.2 2001/07/27 14:12:13 peter Exp $

#ifndef CTRANSF_HH_
#define CTRANSF_HH

#include "cvector.hh"

class CTransform {
   ... // snipped some stuff here too
   void CreateRotate (const CVector &);
};

#endif

// $Log: ctransf.hh,v $ 

The compiler complains that in ctransf.hh, CVector was not declared in
this scope. More precisely, it complains about a parse error before &.
How come? I do include cvector.hh, I do have the proper pre-processor
directives to avoid multiple inclusion...

I was able to build the project by substituting the includes with
dummy class declarations like 'class CVector;' in ctransf.hh and
'class CTransform;' in cvector.hh, but I am 100% sure this will lead
to terrible memory problems during runtime, even though it linked
properly. Right?

Please help me before I lose all my hair over this problem.


Peter Popov ICQ : 15002700
Personal e-mail : pet### [at] vipbg
TAG      e-mail : pet### [at] tagpovrayorg


Post a reply to this message

From: Johannes Bretscher
Subject: Re: C++ problem
Date: 28 Jul 2001 10:43:32
Message: <45juj9.519.ln@cthulhu.hans.5sl.org>
On Sat, 28 Jul 2001 17:20:21 +0300, Peter Popov wrote:
> I am crossposting this to .programming and .unix because I don't
> really know the source of the problem - my incompetence with C++ or my
> compiler (gcc).
>

The compiler works as expected.
 
> This isn't really POV-related ATM but will be at some point in time.
> Anyway...
> 
> [ snip cross inclusion]
> 
> The compiler complains that in ctransf.hh, CVector was not declared in
> this scope. More precisely, it complains about a parse error before &.
> How come? I do include cvector.hh, I do have the proper pre-processor
> directives to avoid multiple inclusion...

The compiler always will read one header first. But this header
already needs the other one.

> 
> I was able to build the project by substituting the includes with
> dummy class declarations like 'class CVector;' in ctransf.hh and
> 'class CTransform;'

One of them is enough, if you know wich is read first.

 in cvector.hh, but I am 100% sure this will lead
> to terrible memory problems during runtime, even though it linked
> properly. Right?

No. First, you only use references, wich are in fact some sort of
pointers. Then in the first step the compiler needs only to know
which names are defined. The exact memory calculation is done later.
(If you are interestet in the exact point read the gcc info files)

> 
> Please help me before I lose all my hair over this problem.
> 
> 

HTH
  Johannes

-- 
E-Mail: bre### [at] 5slorg     www: http://www.5sl.org/~bretscher
pgp fingerprint = 441A 3B97 811D EC61 DC0A  474B 17C4 EB7F 9BD1 BEAC

God, Root, what is difference?
   Illiad


Post a reply to this message

From: Thorsten Froehlich
Subject: Re: C++ problem
Date: 28 Jul 2001 13:29:23
Message: <3b62f673$1@news.povray.org>
In article <66b5mtg5prajt3ebi52l7imlgmm9tdhnra@4ax.com> , Peter Popov 
<pet### [at] vipbg>  wrote:

> I was able to build the project by substituting the includes with
> dummy class declarations like 'class CVector;' in ctransf.hh and
> 'class CTransform;' in cvector.hh, but I am 100% sure this will lead
> to terrible memory problems during runtime, even though it linked
> properly. Right?

Wrong.  What you did is perfectly OK.

What would a class declaration have to do with memory problems anyway?
I somehow get the impression you are not really sure what declarations do
and don't do in C++ ...


    Thorsten


____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde

Visit POV-Ray on the web: http://mac.povray.org


Post a reply to this message

From: Peter Popov
Subject: Re: C++ problem
Date: 28 Jul 2001 16:34:23
Message: <7u76mtgkps7vufsb0u1ggvfvr6k23e3s2p@4ax.com>
On Sat, 28 Jul 2001 19:29:19 +0200, "Thorsten Froehlich"
<tho### [at] trfde> wrote:

>Wrong.  What you did is perfectly OK.

Yeah, I figured that out in the meantime :)

>What would a class declaration have to do with memory problems anyway?

Well, I thought the linker would get confused where to look for that
class, but it is certainly smarter than me.

>I somehow get the impression you are not really sure what declarations do
>and don't do in C++ ...

I am still learning, but I am pretty certain I do know the difference
between declaring and defining, and where one is allowed and one is
not. Today it took me a while to figure out static members, but am
using them widely already (object counters, such stuff.)

This is still the easy part. Merging it into POV is when I'll really
need help :)


Peter Popov ICQ : 15002700
Personal e-mail : pet### [at] vipbg
TAG      e-mail : pet### [at] tagpovrayorg


Post a reply to this message

From: Warp
Subject: Re: C++ problem
Date: 28 Jul 2001 16:41:56
Message: <3b632394@news.povray.org>
In povray.programming Thorsten Froehlich <tho### [at] trfde> wrote:
: I somehow get the impression you are not really sure what declarations do
: and don't do in C++ ...

  It's a surprisingly common phenomenon that people coding C++ don't really
know what type of code is generated from certain types of things.
  For example many people think that adding a function (ie. method) to a
class increases the size of the class. Although this misconception is
understandable, it's unfortunate, as it may lead to people trying to make
"size optimizations" where it doesn't have the slightest effect and only
makes the code worse.
  There are also other strange misconceptions. For example I have heard
people say that if you use one virtual function in a class, you should make
all functions virtual. I haven't the slightest clue what causes this
thinking, but it has to negative effects: It breaks object-orientedness
(by making functions virtual when they really shouldn't be) and it also
produces a bit slower code (calling a non-virtual function is a bit faster
than a virtual function; it doesn't matter if there are or aren't other
virtual functions in the same class).
  A related misconception is that calling a virtual function is very slow.
Yes, it's a bit slower than calling a regular function, but the speed
difference is usually one or two CPU clocks, which usually doesn't matter,
specially if the function itself takes hundreds of clocks.

  When people have many of these misconceptions and they try to "optimize"
they usually end up writing incredibly bad OO code in vain. They optimize
in really wrong places and make the code really bad.
  This is why it's important to know what type of code is generated from
what you write.

-- 
#macro N(D,I)#if(I<6)cylinder{M()#local D[I]=div(D[I],104);M().5,2pigment{
rgb M()}}N(D,(D[I]>99?I:I+1))#end#end#macro M()<mod(D[I],13)-6,mod(div(D[I
],13),8)-3,10>#end blob{N(array[6]{11117333955,
7382340,3358,3900569407,970,4254934330},0)}//                     - Warp -


Post a reply to this message

From: Thorsten Froehlich
Subject: Re: C++ problem
Date: 28 Jul 2001 18:45:20
Message: <3b634080@news.povray.org>
In article <3b632394@news.povray.org> , Warp <war### [at] tagpovrayorg>  wrote:

>   For example many people think that adding a function (ie. method) to a
> class increases the size of the class.

Well, this can be true in case virtual functions are added to a class
containing no virtual functions (and the compiler optimized away the storage
for the vtable pointer if it wasn't used) and when inheriting from other
class(es) class sizes can grow because of vtables and different
this-pointers.

>   A related misconception is that calling a virtual function is very slow.
> Yes, it's a bit slower than calling a regular function, but the speed
> difference is usually one or two CPU clocks, which usually doesn't matter,
> specially if the function itself takes hundreds of clocks.

Of course, you assume the vtable is in the cache and the processor supports
the necessary indirect addressing modes.

>   This is why it's important to know what type of code is generated from
> what you write.

Yes, and it is equally important to know that a linker will warn the user if
it finds duplicate symbols.  After all, without a good linker C++ cannot be
very efficient (i.e. not having duplicate vtables for every file that uses
the same class).

I think this was Peter's assumption.  Fortunately symbol names would be
identical in this case and he would have gotten a proper warning from the
linker if there would have been a problem.

    Thorsten

____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde

Visit POV-Ray on the web: http://mac.povray.org


Post a reply to this message

From: Warp
Subject: Re: C++ problem
Date: 28 Jul 2001 20:23:15
Message: <3b635773@news.povray.org>
In povray.unix Thorsten Froehlich <tho### [at] trfde> wrote:
: Well, this can be true in case virtual functions are added to a class
: containing no virtual functions (and the compiler optimized away the storage
: for the vtable pointer if it wasn't used) and when inheriting from other
: class(es) class sizes can grow because of vtables and different
: this-pointers.

  I didn't mean this. I meant that they think that a class with 20 methods
takes more space than a class with 10 methods.

  Of course making the class virtual increases its size (in practice by
the size of a pointer). It doesn't matter, however, how many virtual
functions you put inside it, it will not take any extra space.

: Of course, you assume the vtable is in the cache and the processor supports
: the necessary indirect addressing modes.

  If the vtable isn't in the cache, then the function to be called will
probably not be either, so it usually doesn't make that big difference
(compared to a non-virtual function, I mean).

  Of course one has to be aware of the fact that virtual classes are not
totally free. Usually it's not a good idea to make a method virtual just
for the sake of it, specially if it's time-critical. Also making a class
virtual just for the sake of it may not be a good idea if space is a critical
issue (eg. the class itself is very small and millions of instances are
created from that class).
  Using virtual functions in a class increases the size of the class (usually
by one pointer). With very space-critical classes this has to be noted.
  Calling a virtual function can be a bit slower than a regular function,
although it usually isn't considerable slowdown.
  Virtual functions most probably can't be inlined (although this is one
detail where I'm not 100% sure).

  Virtual inheritance is a story on its own...

-- 
#macro N(D,I)#if(I<6)cylinder{M()#local D[I]=div(D[I],104);M().5,2pigment{
rgb M()}}N(D,(D[I]>99?I:I+1))#end#end#macro M()<mod(D[I],13)-6,mod(div(D[I
],13),8)-3,10>#end blob{N(array[6]{11117333955,
7382340,3358,3900569407,970,4254934330},0)}//                     - Warp -


Post a reply to this message

From: Thorsten Froehlich
Subject: Re: C++ problem
Date: 29 Jul 2001 04:45:35
Message: <3b63cd2f$1@news.povray.org>
In article <3b635773@news.povray.org> , Warp <war### [at] tagpovrayorg>  wrote:

> : for the vtable pointer if it wasn't used) and when inheriting from other
> : class(es) class sizes can grow because of vtables and different
> : this-pointers.
<snip>
>   Virtual inheritance is a story on its own...

Yes, and one that isn't very well explained anywhere but in the source code
of compilers :-(


      Thorsten


____________________________________________________
Thorsten Froehlich, Duisburg, Germany
e-mail: tho### [at] trfde

Visit POV-Ray on the web: http://mac.povray.org


Post a reply to this message

From: Warp
Subject: Re: C++ problem
Date: 29 Jul 2001 07:20:50
Message: <3b63f192@news.povray.org>
In povray.programming Thorsten Froehlich <tho### [at] trfde> wrote:
: Yes, and one that isn't very well explained anywhere but in the source code
: of compilers :-(

  You might already know what virtual inheritance does, but let me explain it
anyways in case anyone is interested (which I doubt, but for some reason I
like to write these kind of things... :) ).

  Virtual inheritance (class B: virtual public A) by itself doesn't do
anything, and it has effect exclusively when using the so-called "diamond
inheritance", that is, when making multiple inheritance from classes with a
common base class. Any other use of virtual inheritance has no effect.

  The idea is the following:

  Suppose that you have a class like this:

class A
{
 public:
    void modify_x();

 private:
    int x;
};

  Now we make regular inheritance to create the classes B and C:

class B: public A { public: void f(); ... };
class C: public A { public: void g(); ... };

  Both will have their own "copy" of A, that is, in practice their own
copy of the "x" variable. That is, the structure of the B class will be
like this (ascii-art follows):

B:
,----------------------,
| A-part : int x       |
|----------------------|
| B-part : B variables |
`----------------------'

  The C class will be similar. Also suppose that the f() function in B
calls modify_x() to modify the x variable inside B and similarly the g()
function calls modify_x() to modify the x variable inside C.

  Now if we make a class D which is inherited from both B and C, ie:

class D: public B, public C { ... }

the structure of D will look like this:

D:
,----------------------,
| A-part : int x       |
|----------------------|
| B-part : B variables |
|----------------------|
| A-part : int x       |
|----------------------|
| C-part : C variables |
|----------------------|
| D-part : D variables |
`----------------------'

  The x variable will appear twice in the class, once for B and once for C.
If we call f(), it will modify (through modify_x()) the first x, and if we
call g(), it will modify the second x. Modifying one will not affect the
other.

  Sometimes this is exactly the behaviour one wants. This is usually so if
D is not interested in the x variable, but it's used exclusively for internal
calculations of B and C.
  However, sometimes this is not what one wants, specially if D is interested
in x. In this case one would want the x variable to appear just once in D and
both f() and g() should modify the same x.
  This is where virtual inheritance kicks in. It's used specifically for this
purpose. It works like this:

  If we know that a "diamond inheritance" will be used for B and C and that the
variables of A should appear only once in the final class, they have to be
inherited virtually, that is:

class B: virtual public A { public: void f(); ... };
class C: virtual public A { public: void g(); ... };

  The class D is inherited from B and C in the regular way (ie. it doesn't need
to be inherited virtually).
  After this modification D will look like this:

D:
,----------------------,
| A-part : int x       |
|----------------------|
| B-part : B variables |
|----------------------|
| C-part : C variables |
|----------------------|
| D-part : D variables |
`----------------------'

  Now both f() and g() will modify the same x variable instead of having an own
copy of it.

  This might look simple, but if one begins to think about how this can be
implemented at low-level, one will soon realize that it's far from simple.
  This is because when f() is called, the function f() sees only the "B-part"
of the class, nothing else (in practice 'this' will point to the beginning of
"B-part" instead of the beginning of the whole D class). Thus it can't directly
know where x is located (because it's no longer located in the B-part but
somewhere else). Similarly the g() function, which should modify the same x,
can't know its location directly because it's not inside the C-part either.


-- 
#macro N(D,I)#if(I<6)cylinder{M()#local D[I]=div(D[I],104);M().5,2pigment{
rgb M()}}N(D,(D[I]>99?I:I+1))#end#end#macro M()<mod(D[I],13)-6,mod(div(D[I
],13),8)-3,10>#end blob{N(array[6]{11117333955,
7382340,3358,3900569407,970,4254934330},0)}//                     - Warp -


Post a reply to this message

From: Mr  Art
Subject: Re: C++ problem
Date: 29 Jul 2001 07:43:41
Message: <3B642F5E.EAB06B0A@chesapeake.net>
I liked the explanation. Seemed to make sense.

Warp wrote:
> 
> In povray.programming Thorsten Froehlich <tho### [at] trfde> wrote:
> : Yes, and one that isn't very well explained anywhere but in the source code
> : of compilers :-(
> 
>   You might already know what virtual inheritance does, but let me explain it
> anyways in case anyone is interested (which I doubt, but for some reason I
> like to write these kind of things... :) ).
>


Post a reply to this message

Goto Latest 10 Messages Next 3 Messages >>>

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.