Virtual functions and inheritance using the new and delete operators | developer.brewmp.com Virtual functions and inheritance using the new and delete operators | developer.brewmp.com

Developer

Virtual functions and inheritance using the new and delete operators

Forums:

Ok, I've been told that virtual functions don't work in Brew, so to test it, I decided to play around a little. I found that they do work... after a fashion.

Here's my setup.

Parent (a pure virtual class with a declaration of virtual void foo() = 0; ) .

Child (fills in foo) -> Parent

Grandchild (fills in foo, overrideing Child::Foo()) -> Child.

I'm using virtual destructors. Now, here's the problem. I loaded my test app onto a phone, and had some interesting results. When I use dbgprintf's to see whats going on, i get my cascading constructors for a declaration of:

Child theChild;
Grandchild theGrandchild;
Child * pTheChild = new Child();
Grandchild * pTheGrandchild = new Grandchild();

Next, I call foo, which prints out a friendly message, (hello for child, and hewwo for grandchild). Now, I want to call Foo() as if I had no idea what the actual class of the object was, so I cast it as a Parent:

((Parent*)&theChild)->Foo();
((Parent*)&theGrandchild)->Foo();

-and-

((Parent*)pTheChild)->Foo();
((Parent*)pTheGrandchild)->Foo();

The interesting thing that happens, is I get a response from theChild and theGrandchild, but the phones crash on the pointer references on pTheChild and pTheGrandchild.

I figured it might have something do to with my calling of that method, and the program properly constructed all four objects, and then destroyed the first two, and once again crashed when I tried to destroy the two pointers to the objecs.

I'm using:

delete pTheChild;
delete pTheGrandchild;

to delete them. The interesting part is that the destructors work for the local, statically allocated objects.

I was wondering if anyones had a similar experience and has a good workaround/idea why thats happening.

Thanks,
~James Maki

I haven't used C++ virtual methods on a phone, but based on what you are describing it sure sounds like they don't work.
Typically, when you create a that has virtual methods (ie: a vtable), the call to new() allocates a bit of additional space in front of the pointer to hold some sort of pointer to the vtable for that class.
My guess would be that the implementation of new() that you are getting isn't correctly setting up the vtable, or perhaps the compiler doesn't generate the vtables.
Are you using gcc?

I haven't used C++ virtual methods on a phone, but based on what you are describing it sure sounds like they don't work.
Typically, when you create a that has virtual methods (ie: a vtable), the call to new() allocates a bit of additional space in front of the pointer to hold some sort of pointer to the vtable for that class.
My guess would be that the implementation of new() that you are getting isn't correctly setting up the vtable, or perhaps the compiler doesn't generate the vtables.
Are you using gcc?

No, I'm using the ARM compiler.
What your saying makes sense, but I'm still wondering about why my new override would fail on virtual calls and yet the statically constructed objects would cascade the virtual functions properly, and in fact, call other virtual functions without problems.
~James Maki
Chasma.com

No, I'm using the ARM compiler.
What your saying makes sense, but I'm still wondering about why my new override would fail on virtual calls and yet the statically constructed objects would cascade the virtual functions properly, and in fact, call other virtual functions without problems.
~James Maki
Chasma.com

I'm not sure who said that, but it's definitely incorrect.
Virtual functions work just fine in Brew. I have yet to find any C++-related language feature that is not supported, except for exceptions.

I'm not sure who said that, but it's definitely incorrect.
Virtual functions work just fine in Brew. I have yet to find any C++-related language feature that is not supported, except for exceptions.

We use use virtual functions and pure virtual functions often in our application (a very large one) and so far I did not have any problem in running the application in BREW device. ARM compiler supports embedded C++ specification .
See the following link for ARM compiler features
http://www.arm.com/pdfs/DUI0171B_RVCT_BREW_CompLib.pdf
ruben

We use use virtual functions and pure virtual functions often in our application (a very large one) and so far I did not have any problem in running the application in BREW device. ARM compiler supports embedded C++ specification .
See the following link for ARM compiler features
http://www.arm.com/pdfs/DUI0171B_RVCT_BREW_CompLib.pdf
ruben

Is it necessary to do anything special to overload the new and delete operators? It seems like that might be part of the problem. It seems that way because, if i set int data = 1 in Parent, then set it to 2 in child, and 3 in grandchild, when I use the new operator, and call method Bar that prints data out, it prints random data, instead of printing 2 or 3, even tho the constructors were called to set this data correctly.
These are the overloads we are using
void *operator new ( size_t size)
{
return MALLOC (size) ;

void operator delete(void * ptr)
{
FREE(ptr) ;

~James Maki
Chasma.com

Is it necessary to do anything special to overload the new and delete operators? It seems like that might be part of the problem. It seems that way because, if i set int data = 1 in Parent, then set it to 2 in child, and 3 in grandchild, when I use the new operator, and call method Bar that prints data out, it prints random data, instead of printing 2 or 3, even tho the constructors were called to set this data correctly.
These are the overloads we are using
void *operator new ( size_t size)
{
return MALLOC (size) ;

void operator delete(void * ptr)
{
FREE(ptr) ;

~James Maki
Chasma.com

So I found my problem I guess. As it turns out, BREW supports virtual functions, but not all phones do. I took my application, which had been crashing on the Motorola C343, and put it on the Audiovox 9900, and it ran beautifully.
I would be kind of interested in building a table of which phones DO support it, and those that don't.
~james

So I found my problem I guess. As it turns out, BREW supports virtual functions, but not all phones do. I took my application, which had been crashing on the Motorola C343, and put it on the Audiovox 9900, and it ran beautifully.
I would be kind of interested in building a table of which phones DO support it, and those that don't.
~james

That is not possible. The implementation of your virtual functions is created by the compiler not the phone. The problem has to lie somewhere else in that case.

That is not possible. The implementation of your virtual functions is created by the compiler not the phone. The problem has to lie somewhere else in that case.

I don't understand how thats not possible. If the exact same .mod file runs on one phone and not the other, how can that not be a phone specific problem? I mean, its not like these phones all implement brew the same way. Take for example, GetFontMetrics(). That crashes some phones, and returns 0 on the 343. There are many other examples of BREW not working correctly on some phones, but if you think there's something I can do to make it work, I'd be glad to hear of it. Also, Dragon, I'm wondering what devices you develop for?
~james

I don't understand how thats not possible. If the exact same .mod file runs on one phone and not the other, how can that not be a phone specific problem? I mean, its not like these phones all implement brew the same way. Take for example, GetFontMetrics(). That crashes some phones, and returns 0 on the 343. There are many other examples of BREW not working correctly on some phones, but if you think there's something I can do to make it work, I'd be glad to hear of it. Also, Dragon, I'm wondering what devices you develop for?
~james

I do have virtual function running on the c343, and to answer your question I have created versions for virtually all Brew color handsets - some 30-odd ones.
So, to come back to the original problem, what you are experiencing is most likely a probelm with the phone's firmware but it has nothing to do with virtual functions per se. Just think about it for a second. What are virtual functions, and how are they created? Once you understand that you will see that it is impossible for one handset to execute them and for another to skip them. Virtual functions - as I said before - are created by the compiler! They are not Brew-related at all.
I suspect that in your particular case you are doing something IN these virtual functions that is not working properly on that particular handset. You must not confuse one problem with another. Maybe you're making a call to some API function that is not properly implemented on the c343, causing the odd behavior.

I do have virtual function running on the c343, and to answer your question I have created versions for virtually all Brew color handsets - some 30-odd ones.
So, to come back to the original problem, what you are experiencing is most likely a probelm with the phone's firmware but it has nothing to do with virtual functions per se. Just think about it for a second. What are virtual functions, and how are they created? Once you understand that you will see that it is impossible for one handset to execute them and for another to skip them. Virtual functions - as I said before - are created by the compiler! They are not Brew-related at all.
I suspect that in your particular case you are doing something IN these virtual functions that is not working properly on that particular handset. You must not confuse one problem with another. Maybe you're making a call to some API function that is not properly implemented on the c343, causing the odd behavior.

C++ virtual functions do work in BREW, just as
normal C++ programs. However, dependend on
which compiler you are using, you might need
to overload operater new and operater new[] both,
(as well as operator delete and operator delete[]).
Regards.

C++ virtual functions do work in BREW, just as
normal C++ programs. However, dependend on
which compiler you are using, you might need
to overload operater new and operater new[] both,
(as well as operator delete and operator delete[]).
Regards.

Hi
Did you try something like this:
Parent * pTheChild = new Child();
Parent * pTheGrandchild = new Grandchild();
pTheChild->Foo();
pTheGrandchild->Foo();
Does above code crashes the phone, or it calls right Foo()'s of the Child and Grandchild? Since you #defined 'new' to MALLOC(), you may want to call a "second phase" constructor separately to fill in some initial values, if that is what your objects need.
BTW, not that I'm Dragon's fan, but it can be very useful to listen to what he's saying...

Hi
Did you try something like this:
Parent * pTheChild = new Child();
Parent * pTheGrandchild = new Grandchild();
pTheChild->Foo();
pTheGrandchild->Foo();
Does above code crashes the phone, or it calls right Foo()'s of the Child and Grandchild? Since you #defined 'new' to MALLOC(), you may want to call a "second phase" constructor separately to fill in some initial values, if that is what your objects need.
BTW, not that I'm Dragon's fan, but it can be very useful to listen to what he's saying...

c@ini@o,
If you overload new and delete operators you should always properly overload - and use - both the new and new[] operators because they are two very different things. It is unrelated to the compiler per se, really, though some runtime environments are more forgiving about the mistake of not doing it than others.

c@ini@o,
If you overload new and delete operators you should always properly overload - and use - both the new and new[] operators because they are two very different things. It is unrelated to the compiler per se, really, though some runtime environments are more forgiving about the mistake of not doing it than others.

ThePhoneWiz,
It does indeed crash the phone. I'm still trying to muck around. Haven't even began to come up with a fix yet. However, that second phase constructor sounds like a good idea, however, I already know that my constructors are cascading correctly. Its any calls to virtual functions that crash.
~james

ThePhoneWiz,
It does indeed crash the phone. I'm still trying to muck around. Haven't even began to come up with a fix yet. However, that second phase constructor sounds like a good idea, however, I already know that my constructors are cascading correctly. Its any calls to virtual functions that crash.
~james

Hi
Quote:It does indeed crash the phone.
Hmm, try this:
Parent * pTheChild = new Child();
Parent * pTheGrandchild = new Grandchild();
DBGPRINTF("pTheChild: %u", pTheChild);
DBGPRINTF("pTheGrandchild: %u", pTheGrandchild);
if (pTheChild)
pTheChild->Foo();
if (pTheGrandChild)
pTheGrandchild->Foo();
BTW, phone is rebooted, it's not the watchdog who "crashes" it because Foo() takes too long (or the whole event handling takes too long)?

Hi
Quote:It does indeed crash the phone.
Hmm, try this:
Parent * pTheChild = new Child();
Parent * pTheGrandchild = new Grandchild();
DBGPRINTF("pTheChild: %u", pTheChild);
DBGPRINTF("pTheGrandchild: %u", pTheGrandchild);
if (pTheChild)
pTheChild->Foo();
if (pTheGrandChild)
pTheGrandchild->Foo();
BTW, phone is rebooted, it's not the watchdog who "crashes" it because Foo() takes too long (or the whole event handling takes too long)?

Thanks for the tip. It brings up some interesting data
This is for my "Child theChild":
Location: 16989016
Data is 2
Child->Foo
This is the "Grandchild theGrandchild":
Location: 16989008
Data is 3
Grandchild->Foo
This is the "Child * pTheChild = new Child()". This is also where the phone starts to hate life:
Location: 3852464200
Data is 0
At this point, where it tries to call Foo, it soft resets. Which kinda makes sense now that I see the address its supposed to be residing in. My quesiton is, why is the address returned from the new() so high?
I think its about time I include the project i'm working with. I'm attaching a zip if anyones interested in looking.
~james
P.S. "Data is x" is just a call to a Bar() method from Parent that prints out a data member that is set in the constructor of each class. Parent = 1, Child = 2, Grandchild = 3.

Thanks for the tip. It brings up some interesting data
This is for my "Child theChild":
Location: 16989016
Data is 2
Child->Foo
This is the "Grandchild theGrandchild":
Location: 16989008
Data is 3
Grandchild->Foo
This is the "Child * pTheChild = new Child()". This is also where the phone starts to hate life:
Location: 3852464200
Data is 0
At this point, where it tries to call Foo, it soft resets. Which kinda makes sense now that I see the address its supposed to be residing in. My quesiton is, why is the address returned from the new() so high?
I think its about time I include the project i'm working with. I'm attaching a zip if anyones interested in looking.
~james
P.S. "Data is x" is just a call to a Bar() method from Parent that prints out a data member that is set in the constructor of each class. Parent = 1, Child = 2, Grandchild = 3.

Ok. Finally Fixed my problem.
It turns out that I needed to overload my New and Delete operator for each inherited class. Why this is neccessary, why I just can't globally define my New and Delete is beyond me, but anyways, there it is.
Don't know why I didn't try that sooner.
~james

Ok. Finally Fixed my problem.
It turns out that I needed to overload my New and Delete operator for each inherited class. Why this is neccessary, why I just can't globally define my New and Delete is beyond me, but anyways, there it is.
Don't know why I didn't try that sooner.
~james

Glad you got it to work.

Glad you got it to work.

Dragon:
I agree with your statement that some
runtime env are more forgiven than
others. But in my opinion the compiler
should do a better job to prevent
the programmer to made such mistake.
For instance, if you overload just
operater new but not operator new[]
and if you do a :
char* ptr = new char[NUM];
C++ standard requires operator new[] to
be used. MSVC 6.0 will let you get away
but gcc 3.2 will complain.
I developed my program in msvc and
everything worked fine until one day I
use the (arguably better) gcc.
Regards.

Dragon:
I agree with your statement that some
runtime env are more forgiven than
others. But in my opinion the compiler
should do a better job to prevent
the programmer to made such mistake.
For instance, if you overload just
operater new but not operator new[]
and if you do a :
char* ptr = new char[NUM];
C++ standard requires operator new[] to
be used. MSVC 6.0 will let you get away
but gcc 3.2 will complain.
I developed my program in msvc and
everything worked fine until one day I
use the (arguably better) gcc.
Regards.

eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%61%6b%69%5f%6a%40%63%68%61%73%6d%61%2e%63%22%3e%6d%61%6b%69%5f%6a%40%63%68%61%73%6d%61%2e%63%3c%2f%61%3e%27%29%3b')):
Glad that you make it work. I think in
order to avoid overloading operator new
for each classes, you need to make sure
that you are overloading the operator new
in the same namespace as you define your
classes. (It is probably the global
namespace, unless you are using GNU's
ARM compiler).
Regards.

eval(unescape('%64%6f%63%75%6d%65%6e%74%2e%77%72%69%74%65%28%27%3c%61%20%68%72%65%66%3d%22%6d%61%69%6c%74%6f%3a%6d%61%6b%69%5f%6a%40%63%68%61%73%6d%61%2e%63%22%3e%6d%61%6b%69%5f%6a%40%63%68%61%73%6d%61%2e%63%3c%2f%61%3e%27%29%3b')):
Glad that you make it work. I think in
order to avoid overloading operator new
for each classes, you need to make sure
that you are overloading the operator new
in the same namespace as you define your
classes. (It is probably the global
namespace, unless you are using GNU's
ARM compiler).
Regards.

Quote:It turns out that I needed to overload my New and Delete operator for each inherited class. Why this is neccessary, why I just can't globally define my New and Delete is beyond me, but anyways, there it is.
In my application I use global version of new/delete and it works fine. May be your overloaded version of new/delete header is not getting included in all your C++ header files.
ruben

Quote:It turns out that I needed to overload my New and Delete operator for each inherited class. Why this is neccessary, why I just can't globally define my New and Delete is beyond me, but anyways, there it is.
In my application I use global version of new/delete and it works fine. May be your overloaded version of new/delete header is not getting included in all your C++ header files.
ruben

I can't believe I did that. Thats exactly whats happening. Thanks ruben. I guess thats what I get for going from a C# world directly into a c++ world.
~james

I can't believe I did that. Thats exactly whats happening. Thanks ruben. I guess thats what I get for going from a C# world directly into a c++ world.
~james