C++ "this" pointer off by 4 bytes

Started by
8 comments, last by the_edd 15 years, 9 months ago
I'm trying to make an object that can create a message, and one of the elements of the message is a pointer to the object that created the message. OK? The problem is that when I set the message's pointer to "this" that pointer is off by 4 bytes! To the external world, the object is at the address 0x000dbda40 , but to the internal world "this" points to at 0x000dbda44 I am using inhereitance (lots of objects can create messages and they all derive from a base object), so that might be related to the problem. But the only workaround I can think of is to subtract those 4 bytes off, and I'm not really sure that's safe...
Advertisement
first learn the difference between a bit and a byte.

account (and thread) closed till you have demonstrated this understanding.

contact a forum moderator for further detais.
Everyone hates #1.That's why a lot of idiots complain about WoW, the current president, and why they all loved google so much when it was new.Forget the fact that WoW is the greatest game ever created, our president rocks and the brainless buffons of America care more about how articulate you are than your decision making skills, and that google supports adware, spyware, and communism.
Quote:
account (and thread) closed till you have demonstrated this understanding.

contact a forum moderator for further detais.

I am not amused.

This is not the lounge. If you're not going to do anything but make insepid 'jokes' and pretend like you're a moderator, do not post. I don't expect to see any more off-topic baiting in this thread.
Quote:
I am using inhereitance (lots of objects can create messages and they all derive from a base object), so that might be related to the problem. But the only workaround I can think of is to subtract those 4 bytes off, and I'm not really sure that's safe...

It's not.

There are cases that can cause the this pointer to differ for what is the same aggregate object (for example, multiple inheritance situations, or if you are in the constructor, as the derived classes are not yet constructed).

Can you show us the relevant code? It will be easier to provide some direction.
Quote:Original post by polaris2013
I'm trying to make an object that can create a message, and one of the elements of the message is a pointer to the object that created the message. OK?

The problem is that when I set the message's pointer to "this" that pointer is off by 4 bytes! To the external world, the object is at the address 0x000dbda40 , but to the internal world "this" points to at 0x000dbda44

I am using inhereitance (lots of objects can create messages and they all derive from a base object), so that might be related to the problem. But the only workaround I can think of is to subtract those 4 bytes off, and I'm not really sure that's safe...


May be similar to a problem I had. Long story short, it was because the compiler was using different packing rules across different files, meaning that the compiler had a different idea of what the "this" pointer was supposed to be.
NextWar: The Quest for Earth available now for Windows Phone 7.
Maybe it will help if I post some code (forgive the hungarian, this is for windows and I wanted to be consistent)

[source=cpp]E_VAL CObjectBase::QueueRequest(MESSAGE msg){	if(g_pObjectMessageQueue == NULL) return RET_ERROR;	CMessage* vmsg = new CMessage;	vmsg->m_pRequestingObject = this;	vmsg->m_pRequestingObject = &*this;	vmsg->m_pRequestingObject = static_cast<CObjectBase*>(this);	vmsg->m_pRequestingObject = static_cast<CObjectBase*>(&*this);	vmsg->m_pRequestingObject = dynamic_cast<CObjectBase*>(this);	vmsg->m_pRequestingObject = dynamic_cast<CObjectBase*>(&*this);	vmsg->m_wRequestingObjectType = Get_Type();	vmsg->m_wRequestingObjectMessage = msg;	g_pObjectMessageQueue->QueueRequest(vmsg);	return RET_OK;}


Yes, I went bonkers with typecasting to see if one of them would work. They don't.
As was suggested by this article:
http://carcino.gen.nz/tech/cpp/multiple_inheritance_this.php

edit: some more code (also slightly modified the code that was above before the edit)-

here's the message handler (yea, I know this is unsafe casting, but I don't see any other way to do it)
[source=cpp]void CGame::UpdateState(DWORD msec){	//iterate through requests until NULL is returned	while(m_pMessageQueue->PeekRequest())	{		CMessage* msg = m_pMessageQueue->PopRequest();		CRegion* r;		switch(msg->m_wRequestingObjectMessage)		{		case MSG_MAPCHANGE:			r = (CRegion*)msg->m_pRequestingObject;			ChangeMap(r->Get_PointerIndex());			break;		}	}}


Here's an example call:
[source=cpp]CRegion* region;//allocate it somehowregion->QueueRequest(MSG_MAPCHANGE);


Also SC4Freak, I'm not doing any manual byte aligning so I think it is unlikely to be the same as your problem.

edit #2: The problem is that the wrong address is stored in CObjectBase::QueueRequest(), because the this pointer is not the same as the pointer in the example call

edit #3: now that I wrote it all down like that I see an obvious workaround that avoids using the "this" pointer, but I would still like to know why this happened for future reference.

[Edited by - polaris2013 on July 12, 2008 9:03:01 PM]
Off hand, I can't see any reason why "this", "region", and "r" in
CRegion* region;//allocate it somehowvmsg->m_pRequestingObject = this;r = (CRegion*)msg->m_pRequestingObject;


would be different. So either I missed something or there is something you have not showed us.

At the very least, when you call
region->QueueRequest(...)


"region" and "this" within the function must have the exact same value. (I havent worked with a bazillion compilers but I don't know any that don't implement "this" that way and I don't event want to imagine how it could be implemented any other way)

However it's possible that something inadvertently changes the value of "m_pRequestingObject" after you have set it to "this"
Are you using multiple inheritance with "multiple" virtual functions? In that case this is perfectly valid.

A pointer of a derived class with multiple virtual tables cast down to one of the base classes will have a slightly offset address to make up for the "other" virtual table.

Compare the type of this to the type of m_pRequestingObject.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

If you are upcasting the 'this' pointer, you can get the behavior you are describing (as other people have mentioned).

Here is a very quick example that shows the same problem:

#include <iostream>using std::cout;using std::endl;class A{public:    virtual void functionone() {}};class B{    virtual void functiontwo() {}};class C : public A, public B{public:    C()    {        class B* b = this;        cout << b << endl;    }    virtual void functionone() { }    virtual void functiontwo() { }};int main(int argc, char** argv){    C* c = new C();    cout << c << endl;    delete c;    return 0;}


At least in VS2005, this shows a 4 byte difference due to casting 'this' up to a B*, because to do so it must skip over the memory occupied by A and return a pointer to the B portion of C. If A actually had some member variables, the difference in the addresses would be even larger, but currently all A has is its vtable pointer.
Try this:

void *creator = dynamic_cast<void *>(this);


This returns a pointer to the address of the most derived object (assuming you have virtual functions in your hierarchy).

This topic is closed to new replies.

Advertisement