"this" pointer changed?

Discuss the development of new homebrew software, tools and libraries.

Moderators: cheriff, TyRaNiD

Post Reply
Criptych
Posts: 64
Joined: Sat Sep 12, 2009 5:18 am

"this" pointer changed?

Post by Criptych »

This is really more a general programming question, but it's a PSP application, so I thought I'd ask here. For starters, I have the following class:

Code: Select all

class Viewpoint
{
public:
   Viewpoint(int source) { Viewpoint(source, 0, 0, 0); }
   Viewpoint(int source, float zoom, float lon, float lat);

   void Scroll(float x, float y);
   void Zoom(float step);
   void Project(int &tx, int &ty, int &tz, int &ts, int &px, int &py);

   int source; float zoom, scale, lon, lat;
};
Now, in my main function, I create a Viewpoint, and call Project on it each frame. Since it was giving me strange results (usually crashes!), I added some debug messages, and got this in my output:

Code: Select all

Viewpoint.cpp:45: Viewpoint::Viewpoint(0x9fbfd88): zoom == 0.000000, scale == 1.000000, lon == 0.000000, lat == -0.000046
Viewpoint.cpp:87: Viewpoint::Project(0x9fbfddc): zoom == 0.000000, scale == 0.000000
The values in parentheses are the "this" pointer at each call. What I don't understand is why, when I only created one Viewpoint in the entire program, "this" has a different value in Project than it did in the constructor? I've tried creating it on the stack and on the heap, but it happens in both cases, and I've never seen it before.
User avatar
jbit
Site Admin
Posts: 293
Joined: Sat May 28, 2005 3:11 am
Location: København, Danmark
Contact:

Post by jbit »

Without more code it's impossible to tell.... However it could be memory corruption (over running a buffer?) or pointer screw up.. but since the pointers are quite close together my guess is you're doing something like...

Code: Select all

Viewpoint *view = new Viewpoint();
view++;
view->Project();
Criptych
Posts: 64
Joined: Sat Sep 12, 2009 5:18 am

Post by Criptych »

But I don't have any pointer manipulations. The section where it's used looks like this (parts removed for brevity):

Code: Select all

   Viewpoint view(0);

   while (running)
   {
      // update animations, etc.

      if (pressed(PSP_CTRL_LEFT))  view.Scroll(-1, 0);
      if (pressed(PSP_CTRL_RIGHT)) view.Scroll(+1, 0);
      if (pressed(PSP_CTRL_UP))    view.Scroll(0, -1);
      if (pressed(PSP_CTRL_DOWN))  view.Scroll(0, +1);
      if (pressed(PSP_CTRL_LTRIGGER)) view.Zoom(-1);
      if (pressed(PSP_CTRL_RTRIGGER)) view.Zoom(+1);

      int tx, ty, tz, ts, px, py;
      view.Project(tx, ty, tz, ts, px, py);

      startDrawing();

      for &#40;int j = -1; j <= 1; j++&#41;
      &#123;
         for &#40;int i = -1; i <= 1; i++&#41;
         &#123;
            getTile&#40;view.source, tz, tx + i, ty + j&#41;->Draw&#40;px + i*ts, py + j*ts, ts, ts&#41;;
         &#125;
      &#125;

      // show coordinate info

      endDrawing&#40;&#41;;
      swapBuffers&#40;&#41;;
   &#125;
The code worked fine with a struct, but it was a little messy, so I was trying to get some encapsulation going. I don't want to go back if I can help it, though.
psPea
Posts: 60
Joined: Sat Sep 01, 2007 12:51 pm

Post by psPea »

I think

Code: Select all

   Viewpoint&#40;int source&#41; &#123; Viewpoint&#40;source, 0, 0, 0&#41;; &#125; 
   Viewpoint&#40;int source, float zoom, float lon, float lat&#41;; 
looks very messy, you should use

Code: Select all

   Viewpoint&#40;int source, float zoom = 0, float lon = 0, float lat = 0&#41;; 
instead
Criptych
Posts: 64
Joined: Sat Sep 12, 2009 5:18 am

Post by Criptych »

Well, it's been a while since I've used C++ to this extent, I guess I'm used to the C# way of doing it. :)

EDIT: Added more debug messages, and now it seems that the constructor is the only place where "this" points somewhere different. All other calls have the same address as the "real" address of the object.
Could I have just been (un)lucky enough to stumble on an obscure compiler bug? As I said, I have never seen this happen before; I have half a dozen other classes in my project, and none of them has exhibited the same problem.

I also found a little workaround that is helping, but I'm still curious about why this happened.
psPea
Posts: 60
Joined: Sat Sep 01, 2007 12:51 pm

Post by psPea »

Maybe this is only initialized after the constructor returns.
Criptych
Posts: 64
Joined: Sat Sep 12, 2009 5:18 am

Post by Criptych »

psPea wrote:Maybe this is only initialized after the constructor returns.
I think it's supposed to be an idiom/placeholder rather than an actual variable to be "initialized." So it should point to "this" object no matter when it's used. Right?
User avatar
jbit
Site Admin
Posts: 293
Joined: Sat May 28, 2005 3:11 am
Location: København, Danmark
Contact:

Post by jbit »

Ugh, didn't notice you were doing odd things..... calling a constructor C# style does not do what you think it does!

Code: Select all

class Test
&#123;
        int m_iVar;
public&#58;
        Test&#40;int var&#41;
        &#123;
                printf&#40;"fake&#58; %p\n", this&#41;;
                m_iVar = var;
        &#125;
        Test&#40;&#41;
        &#123;
                m_iVar = 0;
                printf&#40;"mine&#58; %p\n", this&#41;;
                Test&#40;1&#41;;
        &#125;
        void foo&#40;&#41;
        &#123;
                printf&#40;"using&#58; %p &#40;%d&#41;\n", this, m_iVar&#41;;
        &#125;
&#125;;
int main&#40;&#41;
&#123;
        Test t;
        t.foo&#40;&#41;;
&#125;
prints

Code: Select all

mine&#58; 0xbffff8cc
fake&#58; 0xbffff89c
using&#58; 0xbffff8cc &#40;0&#41;
The constructor call inside the constructor makes a new object on the stack, calls the constructor on that, and then deletes it....

edit: Also, I can't see this working in C# either, as far as I know the only way to do this in C# would be constructor chaining which is:

Code: Select all

class Test
&#123;
    int m_iVar;
public&#58;
   Test&#40;int var&#41; &#123; m_iVar = var; &#125;
   Test&#40;&#41; &#58; this&#40;1&#41;  &#123;&#125;
&#125;;
But as said above, the preferred (and simplest) way for this specific use case is to use default arguments ( Test(int var = 1) ).
Criptych
Posts: 64
Joined: Sat Sep 12, 2009 5:18 am

Post by Criptych »

jbit wrote:The constructor call inside the constructor makes a new object on the stack, calls the constructor on that, and then deletes it....
>.< That explains it, then.
jbit wrote:edit: Also, I can't see this working in C# either, as far as I know the only way to do this in C# would be constructor chaining
That's what I was trying to do, but I couldn't remember the C++ syntax (and was too busy/lazy/distracted at the time to JFGI). Since what I wrote compiled, I thought I'd gotten it.

EDIT: And now having done so, I learn that there is no syntax for it. Bah. :P

Thanks for your help. :)
Post Reply