Archived

This topic is now archived and is closed to further replies.

Succinct

Were you ever convinced that you'd found a compiler bug...

Recommended Posts

Succinct    169
... only to later find out, usually in front of others, that it was more your lack of command of the language? I''m abstracting the Ogl Client/Server model. In my model, clients and classes derived from client connect to the gl "server". Well, the client portion of the classes had the sole responsiblity of delegating connection, disconnection, uploading data to the hardware, and unloading said data. Being that it was responsible for these, when any client was destroyed, the client portion of it was suppossed to make sure the client was disconnected and that it had successfully and completely unloaded itself from the hardware. Heh, unload is a virtual function. It was being called in the client base''s destructor... For those of you who know what''s wrong with this, a very basic c++ programming paradigm error, I give a tip of the hat. Funny stuff to us closet nerds, I''ll tell ya! Thank you for your bandwidth. -- Succinct ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Share this post


Link to post
Share on other sites
alexmoura    450
actually several times - of course, since I am testing a compiler, It turned out to be real bugs quite often

You know, I never wanted to be a programmer...

Alexandre Moura

Share this post


Link to post
Share on other sites
Dormeur    122
It''s not a bug or paradigm error, but it''s just the way C++ virtual functions work. Here''s how I think it goes: virtual functions are accessed through an implicit table (called the vtable) that contains all the virtual functions of the class inheritance tree. When creating and object, the vtable hasn''t been fully constructed, so the wrong virtual function gets called. And that''s why you shouldn''t call virtual functions in the constructor. Same goes for the destructor, but there it''s because the vtable is being cleaned up when destroying the object.

Perhaps an example:
  
#include <iostream>

using namespace std;

class A
{
public:
A() { func(); }
virtual ~A() { func2(); }
virtual void func() { cout << "A::func()" << endl; }
virtual void func2() { cout << "A::func2()" << endl; }
};

class B : public A
{
public:
B() : A() {}
virtual void func() { cout << "B::func()" << endl; }
virtual void func2() { cout << "B::func2()" << endl; }
};

void main()
{
A *a = new B();
delete a;
}


Now you''d expect that the output of this code should be:

B::func()
B::func2()


But it''s not, and that''s because of the vtable stuff. So the actual ouput is:

A::func()
A::func2()


You have no idea how long I''ve searched for bugs in my programs, before I discovered this . Other languages like Java handle this in a much more consequent manner: there the correct virtual function gets called, both in the constructor and the destructor. But I still like C++ better .

Dormeur

Share this post


Link to post
Share on other sites
Succinct    169
Correct!

Being that unload is called in the client''s destructor, the derived portions of the object have been destroyed, and their destructors have already been called.

Worst of all, being that unload is pure virtual at the client base level, I get a system error stating "pure virtual function called".

arrgh.

That''s what I get for being a slow-head and not RTGDFM.

-- Succinct

Share this post


Link to post
Share on other sites
Gorg    248
I just wanted to state that it is valid for only the construtor and the destructor. If you do that any other function, the right virtual function will be called.


It act like this for the constructor and the destructor because of the order of creation :

when you create a derived class, this happens :

1.Base class constructor is called.
2.Derived class constructor is called.

when you destroy it :

1. Derived class is destroyed.
2. Base class is destroyed

look at this example and you will understand why constructor and destructor use only the functions at class level :

  

class Base
{
public:
Base()
{
DoStuff();
}

virtual void DoStuff() = 0;

virtual ~Base()
{
DoStuff();
}
};

class Derived : public Base
{
public:
Derived()
{
myData = new int[40];
}

void DoStuff()
{
for( int i = 0; i < 40; ++i )
{
myData[i] = i;
}
}

~Derived() { delete myData;}
private:
int* myData;
};



See, DoStuff will crap out if called from the constructor or destructor because DoStuff depends on some member attribute.

I don''t see how Java can handle it differently and not cause crashes.

Share this post


Link to post
Share on other sites
Mr Ekted    122
Here''s one I haven''t solved. In VC6 I am unable to declare an array of ints called scr1...

void func ()
{
int scr1[4];

...
}

I get: error C2143: syntax error : missing '';'' before ''constant''

If I change the 1 to another number it works. Either the symbol "scr1" is defined elsewhere, or there''s some internal keyword that I am colliding with. Any thoughts?

Share this post


Link to post
Share on other sites
Gorg    248
quote:
Original post by Mr Ekted
Here''s one I haven''t solved. In VC6 I am unable to declare an array of ints called scr1...

void func ()
{
int scr1[4];

...
}

I get: error C2143: syntax error : missing '';'' before ''constant''

If I change the 1 to another number it works. Either the symbol "scr1" is defined elsewhere, or there''s some internal keyword that I am colliding with. Any thoughts?



I just tried it, including nothing in the file and it compile ok. So there is probably a macro called scr1 from one of your include.

Share this post


Link to post
Share on other sites
Dormeur    122
I don''t know how Java does it, but it works. I''m programming in Java daily at work, and I''m using this feature all the time. I think Java just creates the entire object, including vtables, before actually calling any constructors on the object. Perhaps it''s because Java supports RTTI (Run-time Type Identification) by default, which makes it possible to retrieve info on the classes themselves at runtime, whereas C++ compilers require you to enable it (possibly for performance reasons).

I really think this is so essential to OO programming, that I don''t understand why C++ doesn''t support it.

Dormeur

Share this post


Link to post
Share on other sites
Gorg    248
quote:
Original post by Dormeur
I don''t know how Java does it, but it works. I''m programming in Java daily at work, and I''m using this feature all the time. I think Java just creates the entire object, including vtables, before actually calling any constructors on the object. Perhaps it''s because Java supports RTTI (Run-time Type Identification) by default, which makes it possible to retrieve info on the classes themselves at runtime, whereas C++ compilers require you to enable it (possibly for performance reasons).

I really think this is so essential to OO programming, that I don''t understand why C++ doesn''t support it.

Dormeur


The problem is not the VTable, the problem is having valid objects in those virtual functions.

I will do some test with java later today and post my results.

Share this post


Link to post
Share on other sites
gmcbay    130
The first thing a Java constructor does is call the base classes'' constructor (eg. super(); ).

You can override which base class constructor is called by calling it yourself...Suppose there''s two constructor forms for the base class, one takes a string, one doesn''t, you can be sure the String form is called by calling it yourself:

Derived()
{
super("Blah!");
}


If you don''t specify a constructor form to call, Java will automatically insert a call to the default base constructor for you as the first thing it does, before it runs any other code in your constructor.

Another note..if you DO want to call a specific base constructor, it has to be the first thing you do in the Derived constructor, because Java guarantees that the base constructor will be called before the rest of the Derived constructor is executed:


Derived()
{
i = 0;
super("Blah!");
}


Will result in a compile-time error because Java has to be sure the base class constructor is called before the derived class does anything else.



Share this post


Link to post
Share on other sites
Gorg    248
Java does call the virtual function of the dynamic cast, but if remove the if ( myobj == null ), the code will crap out because myobj does exist until the derived class constructor is called.

It just design decision in language, Java and C++ took different approach.

C++ said, well when you are in the base class constructor we know that the derived class is not created, so when we call a virtual function, it is like we would try to access class member of the derived class. This is obviously pretty bad, so will call the function of the base class.

Java said, we will call the right one, but be carefull and make sure all your object exist when you call a virtual function.

  


class TestObj
{
public TestObj()
{
System.out.println( "TestObj::TestObj()" );
}

public void test()
{
System.out.println( "TestObj::test()" );
}
}

class Base
{
public Base()
{
System.out.println( "Base::Base()" );
doStuff();
}

public void doStuff()
{
System.out.println( "Base::doStuff" );
}
}

class Elem extends Base
{
public Elem()
{
System.out.println( "Base::Elem" );

}

public void doStuff()
{
System.out.println( "Elem::doStuff()" );

if ( myobj != null )
{
myobj.test();
}
}

private TestObj myobj = new TestObj();
}


public class testApp
{
public static void main(String Args[])
{
Elem e = new Elem();

e.doStuff();
}



}

Share this post


Link to post
Share on other sites