Skip to main content
GameDev.net gamedev.net
🔒 Locked

Is the keyword "this" dynamically or statically allocated.

Started by chadsxe Dec 21, 2009 at 1:11 PM 16 replies 2.5k views
Original Post
chadsxe
chadsxe
Hi, I was wondering if the keyword "this" is dynamically or statically allocated. The reason why I ask is I need to store pointer of a class object inside another class object and I was trying to avoid using a raw pointer to store it. For example
class A
{
	B b;

	void Init()
	{
		b.SetA(this);
	}
}

class B
{
	void SetA(A* aPointer){a = aPointer};
	A* a;
}
So I though I might use a boost::shared_ptr. The confusion comes with the fact that boost::share_ptr is looking for a dynamically allocated object and am wondering what my options are. Regards Chad
Sneftel
Sneftel
Quote:
Original post by chadsxe
Hi,

I was wondering if the keyword "this" is dynamically or statically allocated.

The this pointer points to whichever instance of the class is being operated upon. If that instance was dynamically allocated, then it was dynamically allocated. If it was statically allocated, then it was statically allocated. If it was stack-allocated, it was stack-allocated. If you do not prevent any of these types of allocation, then you cannot assume anything about which type was used.
Quote:
I though I might use a boost::shared_ptr. The confusion comes with the fact that boost::share_ptr is looking for a dynamically allocated object and am wondering what my options are.
Take a look at shared_from_this. HOWEVER, first you should make sure you have a good handle on shared_ptr's semantics independently of issues with allocation. In particular, you should be able to determine why the following code fragment is a bad idea, and what error it will lead to:
MyClass *b = new MyClass;shared_ptr<MyClass> sp1(b);shared_ptr<MyClass> sp2(b);
qimmer
qimmer
I can't see any reason to, that your code shouldn't work?
Besides, why is it important if it is dynamically or statically allocated? it's only a pointer? (4 / 8 bytes (64bit) )
cache_hit
cache_hit
I'm not sure if you're talking about the actual 'this' pointer, or the object it points to. Sneftel already answered about the object it points to.

The actual this pointer itself is allocated statically, but not necessarily on the stack.

You'd think a function such as void Foo::bar() {} takes 0 arguments. But actually, it takes 1 argument, which is the 'this' pointer. It's just that the compiler hides the fact that it's an argument of the function for you. On some platforms, calling a member function uses the __thiscall calling convention, which designates that the pointer be stored in the ecx register. So on those architectures it's neither on the stack nor the heap.
cache_hit
cache_hit
Also, your options are either:

a) use a raw pointer if NULL is a valid value
b) use a raw reference if it doesn't need to be assigned except during construction / initialization
c) use boost::ref if NULL is not a valid value, and it does need to be re-assigned multiple times after initialization / construction.
chadsxe
chadsxe
Quote:
Original post by SneftelThe this pointer points to whichever instance of the class is being operated upon. If that instance was dynamically allocated, then it was dynamically allocated. If it was statically allocated, then it was statically allocated. If it was stack-allocated, it was stack-allocated. If you do not prevent any of these types of allocation, then you cannot assume anything about which type was used.


This made sense after you pointed out but leaves me with more questions. For example is there a need to worry about storing a raw pointer to a statically allocated object like there is a need to when storing a raw pointer to a dynamically allocated objected. Besides the obvious scoping concerns that need to be accounted for is it safe to simply null a raw pointer to that statically allocated object once the current holding object does not need it anymore. For example....
class A{	B b;	void Init()	{		b.SetA(this);	}}// This class will always go out of scope before Aclass B{	~B( a = NULL );	void SetA(A* aPointer){a = aPointer};	A* a;}

Quote:
Take a look at shared_from_this. HOWEVER, first you should make sure you have a good handle on shared_ptr's semantics independently of issues with allocation. In particular, you should be able to determine why the following code fragment is a bad idea, and what error it will lead to:
MyClass *b = new MyClass;shared_ptr<MyClass> sp1(b);shared_ptr<MyClass> sp2(b);
I will admit I am scratching my head on this on. But I am looking over the documentation to try and figure it out. When I talk it out I get.

MyClass *b = new MyClass;
Dynamically create a MyClass object and store the address in a raw pointer

shared_ptr sp1(b);
Stores raw pointer in a shared pointer

shared_ptr sp2(b);
Stores raw pointer in another shared pointer

Now if I had to guess I would say there is the possibility of a memory leak do to the fact that the raw pointer b was never considered "Shared". Only sp1 and sp2 are shared. Or not :)

Regards

Chad
Alpha_ProgDes
Alpha_ProgDes
I would guess that the code snippet is the equivalent of this:

int* b = new int;int *a = b;int *c = b;//if you do this:a = NULL;//you break *a, *b, and *c

That's my guess anyway. I'm not familiar with Boost at all.
Beginner in Game Development?  Read here. And read here.  
rip-off
rip-off
If B is always nested inside A, then you should be safe with a raw pointer. I might make B an inner class of A and use access control to ensure that no B instance can exist outside an A.

For Sneftel's puzzle, the answer is that the shared_ptr contructor takes ownership of the raw pointer it is passed. By passing it to two shared_ptrs, they both track it seperately, which will cause undefined behaviour when one of the shared_ptr<> instances thinks the pointer is no longer referenceable and frees it.

Corrected would be this:
MyClass *b = new MyClass;Dynamically create a MyClass object and store the address in a raw pointershared_ptr<MyClass> sp1(b);Stores raw pointer in a shared pointershared_ptr<MyClass> sp2 = sp1;

Sneftel
Sneftel
Quote:
Original post by chadsxe
Now if I had to guess I would say there is the possibility of a memory leak do to the fact that the raw pointer b was never considered "Shared". Only sp1 and sp2 are shared. Or not :)

Nope.

What makes a thing "shared"? Nothing at all. Making a shared_ptr to an object doesn't change it in any way. The object (under normal circumstances) doesn't know it's shared. It doesn't behave any differently. The reference-counted behavior of a shared_ptr is ENTIRELY in shared_ptr. It is not in Object.

So stop thinking about what "shared objects" do, and start thinking about what shared pointers do. What is the difference between the following two snippets?

MyClass *b = new MyClass;shared_ptr<MyClass> sp1(b);shared_ptr<MyClass> sp2(b);


...and...

MyClass *b = new MyClass;shared_ptr<MyClass> sp3(b);shared_ptr<MyClass> sp4(sp3);

Other than being associated with the same object, is there any way in which sp1 and sp2 are associated with each other? Likewise, other than being associated with the same object, is there any way in which sp3 and sp4 are associated with each other?
ChaosEngine
ChaosEngine
Quote:
Original post by Alpha_ProgDes
I would guess that the code snippet is the equivalent of this:

int* b = new int;int *a = b;int *c = b;//if you do this:a = NULL;//you break *a, *b, and *c

That's my guess anyway. I'm not familiar with Boost at all.


Not really. if you do a = NULL, then a is equal to NULL. b still points at a new int and c still points at b.

chadsxe, what happens when the shared_ptrs go out of scope?

if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight
owl
owl
The destructor of the object they point gets called and the object gets deallocated.
[size="2"]I like the Walrus best.
iMalc
iMalc
Quote:
Original post by rip-off
If B is always nested inside A, then you should be safe with a raw pointer. I might make B an inner class of A and use access control to ensure that no B instance can exist outside an A.
Seconded.
chadsxe
chadsxe
Quote:
chadsxe, what happens when the shared_ptrs go out of scope?


I believe when the last share_ptr that is pointing to a dynamically allocated object goes out of scope then that object is deleted.
ChaosEngine
ChaosEngine
Quote:
Original post by chadsxe
Quote:
chadsxe, what happens when the shared_ptrs go out of scope?


I believe when the last share_ptr that is pointing to a dynamically allocated object goes out of scope then that object is deleted.


True. Now what happens when you have two unrelated shared_ptr's pointing to the same object?

void func(){    MyClass *b = new MyClass;    shared_ptr<MyClass> sp1(b); // what is the reference count of sp1 here?    {         shared_ptr<MyClass> sp2(b); // what is the reference count of sp2 here?    } // what happens here?} // more importantly, what happens HERE?

if you think programming is like sex, you probably haven't done much of either.-------------- - capn_midnight
summaky
summaky
Quote:
Original post by ChaosEngine
Quote:
Original post by chadsxe
Quote:
chadsxe, what happens when the shared_ptrs go out of scope?


I believe when the last share_ptr that is pointing to a dynamically allocated object goes out of scope then that object is deleted.


True. Now what happens when you have two unrelated shared_ptr's pointing to the same object?

void func(){    MyClass *b = new MyClass;    shared_ptr<MyClass> sp1(b); // what is the reference count of sp1 here?    {         shared_ptr<MyClass> sp2(b); // what is the reference count of sp2 here?    } // what happens here?} // more importantly, what happens HERE?


And, perhaps, more important is the fact that this "problem" does also happen with std::auto_ptr, which is in the current specification of C++ and thus every C++ programer should know about and understand.

Yes, std::auto_ptr has also its own drawbacks and normally I prefer to use Boost's shared_ptr, unless it makes no sense (and almost always does make sense.)

And those not familiar to Boost's shared_ptr should try to learn it, as it is part of TR1 and thus available in current versions of GCC and Visual Studio (although inside the std::tr1 namespace.) and will be in the next C++ standard.
cache_hit
cache_hit
Quote:
Original post by summaky

Yes, std::auto_ptr has also its own drawbacks and normally I prefer to use Boost's shared_ptr, unless it makes no sense (and almost always does make sense.)


Well auto_ptr and shared_ptr are almost not even comparable because they solve different problems. What you really should be comparing is std::auto_ptr and boost::scoped_ptr. It's not a good idea to use reference counting semantics unless you really need them.

Any time you used to use auto_ptr, you can almost always use scoped_ptr. The rest of the time, you can use std::tr1::unique_ptr. In fact, auto_ptr is officially deprecated in C++0x, and unique_ptr is its official replacement, providing all the good aspects of auto_ptr, while eliminating it's (extremely serious) design flaws of not allowing you to use auto_ptrs in containers.
chadsxe
chadsxe
Quote:
Original post by ChaosEngine
void func(){    MyClass *b = new MyClass;    shared_ptr<MyClass> sp1(b); // what is the reference count of sp1 here?    {         shared_ptr<MyClass> sp2(b); // what is the reference count of sp2 here?    } // what happens here?} // more importantly, what happens HERE?


First a MyClass object is created dynamically and a pointer to it is stored in the variable b. Then a shared_ptr pointer is created referencing b. Giving sp1 a reference count of 1. Then a new share_ptr is created referencing b. Giving sp2 a reference count of 1. Then sp2 goes out of scope and the MyClass object the was created is deleted because sp2 only had a reference count of 1. Finally sp1 goes out of scope and again trys to delete the MyClass object which already had been deleted. And that causes an error.

I believe this is correct?

Regards

Chad
chadsxe
chadsxe
Quote:
Original post by Sneftel
MyClass *b = new MyClass;shared_ptr<MyClass> sp1(b);shared_ptr<MyClass> sp2(b);


...and...

MyClass *b = new MyClass;shared_ptr<MyClass> sp3(b);shared_ptr<MyClass> sp4(sp3);

Other than being associated with the same object, is there any way in which sp1 and sp2 are associated with each other? Likewise, other than being associated with the same object, is there any way in which sp3 and sp4 are associated with each other?


I believe that sp1 and 2 are not associated with each other outside the same object. sp3 and sp4 are which actually ups the reference count.


Regards

Chad

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.