www.digitalmars.com         C & C++   DMDScript  

c++ - problems with local classes

reply John Smith <no spam.com> writes:
Hi,

I have been trying to compile (using 8.42n) some code using several 
local classes. But I have encountered problems with the dmc-compiler. 
Seems like the v-tables aren't stored correctly. Which in my case means 
that the right function isn't called at runtime.


--- dmc_test.cpp ---
#include <iostream>

class A
{
public:
	virtual void a() = 0;
};

int main()
{
	{
		class B : public A
		{
		public:
			void a() { std::cout << "1"; }
		};
		A * a = new B;
		a->a();
		delete a;
	}
	{
		class B : public A
		{
		public:
			void a() { std::cout << "2"; }
		};
		A * a = new B;
		a->a();
		delete a;
	}

	return 0;
}
--- end of snippet ---

This code compiles nicely, but gives the result "11" instead of the 
expected "12". Executables compiled with Mingw 3.4.5, Visual C++ 8.0, 
Borland C++ 5.6.4 and Open Watcom 1.5 all produces the expected output.

  John
Sep 05 2006
next sibling parent reply "Paul McKenzie" <paulm dynasoft.com> writes:
"John Smith" <no spam.com> wrote in message
news:edlid4$gho$1 digitaldaemon.com...
 local classes. But I have encountered problems with the dmc-compiler.

Your code produces undefined behavior. The base class A does not have a virtual destructor, therefore doing this: A *a = new B; //... delete a; // Error. invalidates the rest of the code. You cannot call "delete" on a base class pointer which is pointing to a derived class, unless the base class destructor is virtual. If it isn't virtual, the behavior is undefined (as per ANSI C++ specification -- don't have the time to look up chapter and verse). Change the A class to have a virtual destructor and see if the code works. Even if it doesn't work, you still need the virtual destructor for your code to really be a valid test of whether the compiler is working or not. Paul
Sep 09 2006
next sibling parent John Smith <no spam.com> writes:
The delete-parts of the code was actually an after-construction, added 
when I posted it on the news-board (trying to avoid some irrelevant 
discussion.) The original code did not delete the objects, it just 
leaked them. Another way one is to explicitly cast it back to a B 
pointer in the delete-expression, and therefor fulfilling section 
5.3.5.3, since the static and dynamic types are the same.

Or I could just remove the dynamic allocation all together and write.

		B b;
		A * a = &b;
		a->a();

And I am sure there are other ways of writing this without using virtual 
destructors. But if we were to test out your version, we could even add 
the virtual destructors and see that it isn't even calling the right 
destructor. Since the problem is most likely related to the handling of 
the virtual-tables.

The probability of the virtual destructors being the cause of the 
problem was pretty slim though, if you ask me ;) But thanks for pointing 
that out anyway.

   John
Sep 10 2006
prev sibling parent reply Bertel Brander <bertel post4.tele.dk> writes:
Paul McKenzie wrote:
 "John Smith" <no spam.com> wrote in message
 news:edlid4$gho$1 digitaldaemon.com...
 local classes. But I have encountered problems with the dmc-compiler.

Your code produces undefined behavior. The base class A does not have a virtual destructor, therefore doing this: A *a = new B; //... delete a; // Error.

Are you sure? I'm think it is perfectly legal to have a base class without any destructor. But if you want the destructor of the derevied class to be called upon deletion, if deleted through a base class pointer, you need a virtual destructor in the base class. But it is not undefined behaviour not to have one, the behaviour is perfectly defined; only the destructor of the base class (if any) is called. -- Just another homepage: http://damb.dk But it's mine - Bertel
Sep 10 2006
parent reply "Paul McKenzie" <paulm dynasoft.com> writes:
"Bertel Brander" <bertel post4.tele.dk> wrote in message
news:ee1b50$1c37$1 digitaldaemon.com...
 Are you sure? I'm think it is perfectly legal to have a base class
 without any destructor.
 But if you want the destructor of the derevied class to be called
 upon deletion, if deleted through a base class pointer, you need
 a virtual destructor in the base class. But it is not undefined
 behaviour not to have one, the behaviour is perfectly defined;
 only the destructor of the base class (if any) is called.

From the 1998 ANSI/ISO C++ Standard document. Section 5.3.5 (subsection 3): Delete: In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand's dynamic type and the static type shall have a virtual destructor *or the behavior is undefined.* Paul
Sep 10 2006
parent Bertel Brander <bertel post4.tele.dk> writes:
Paul McKenzie wrote:
 "Bertel Brander" <bertel post4.tele.dk> wrote in message
 news:ee1b50$1c37$1 digitaldaemon.com...
 Are you sure? I'm think it is perfectly legal to have a base class
 without any destructor.
 But if you want the destructor of the derevied class to be called
 upon deletion, if deleted through a base class pointer, you need
 a virtual destructor in the base class. But it is not undefined
 behaviour not to have one, the behaviour is perfectly defined;
 only the destructor of the base class (if any) is called.

From the 1998 ANSI/ISO C++ Standard document. Section 5.3.5 (subsection 3): Delete: In the first alternative (delete object), if the static type of the operand is different from its dynamic type, the static type shall be a base class of the operand's dynamic type and the static type shall have a virtual destructor *or the behavior is undefined.*

I think you are right. But way does all compilers then allow you to compile without a virtual destructor? Just after the section you quote it says: "In the second alternative (delete array) if the dynamic type of the object to be deleted differs from its static type, the behavior is undefined" This seems strange. Why can't you delete an array of a derived class through a pointer to a base class? -- Just another homepage: http://damb.dk But it's mine - Bertel
Sep 10 2006
prev sibling parent reply Jan Knepper <jan smartsoft.us> writes:
Are you building with optimization on?



John Smith wrote:
 Hi,
 
 I have been trying to compile (using 8.42n) some code using several 
 local classes. But I have encountered problems with the dmc-compiler. 
 Seems like the v-tables aren't stored correctly. Which in my case means 
 that the right function isn't called at runtime.
 
 
 --- dmc_test.cpp ---
 #include <iostream>
 
 class A
 {
 public:
     virtual void a() = 0;
 };
 
 int main()
 {
     {
         class B : public A
         {
         public:
             void a() { std::cout << "1"; }
         };
         A * a = new B;
         a->a();
         delete a;
     }
     {
         class B : public A
         {
         public:
             void a() { std::cout << "2"; }
         };
         A * a = new B;
         a->a();
         delete a;
     }
 
     return 0;
 }
 --- end of snippet ---
 
 This code compiles nicely, but gives the result "11" instead of the 
 expected "12". Executables compiled with Mingw 3.4.5, Visual C++ 8.0, 
 Borland C++ 5.6.4 and Open Watcom 1.5 all produces the expected output.
 
  John

-- ManiaC++ Jan Knepper But as for me and my household, we shall use Mozilla... www.mozilla.org
Sep 11 2006
parent John Smith <no spam.com> writes:
No, I am not building it with any optimizations (that I know of). Just 
plain "dmc dmc_test.cpp". I also tried both speed (-o) and space 
(-o+space) optimization-flags without any success.

Jan Knepper wrote:
 Are you building with optimization on?
 
 
 

Sep 12 2006