Sign in to follow this  
RealMarkP

[C++] Checking for 'this' inside it's class

Recommended Posts

Is there a way that I can check if the 'this' keyword was passed into a class (either by checking if the pointer is on the stack, or something)? For example:
MyClass::someFunction()
{
  CSomeOtherClass foo(this);// check if 'this' was passed in as opposed to a pointer variable.
}

I know how to check if a pointer being passed in is on the Stack or the Heap but the 'this' keyword will always be on the Heap if the class itself was dynamically allocated. Is there a way to do this? Possibly using MSVC type traits or something?

Share this post


Link to post
Share on other sites
I am also confused by the question. The thiscall calling convention always stores this in the ECX register, and it follows that you can't take the address of it. If you're already inside a member function and you attempt to call a member function on another instance, then ECX will be pushed onto the stack first so that it can be restored. Also, with thiscall all parameters are pushed onto the stack. But again, I'm still not completely clear on your question.

As others have asked, what exactly is it you're trying to do?

Share this post


Link to post
Share on other sites
You can always check if this == 0

see if it's null.

not sure if that answers your question though either.

the "this" parameter is a hidden argument in your member functions.

IE if you have a member function void Blah(void), in reality (under the hood) the function is void Blah(MyClass *this)

Share this post


Link to post
Share on other sites
I think he's wanting to see if the instance of the class was allocated on the heap (via new, for instance), or whether it was allocated on the stack (passed by value, for instance)

Since you would only have 'this' be on the stack when inside a member function of a class that was passed by value to some function further up the call stack, and the stack grows downwards, I suppose you could check for stack allocation by seeing if 'this' is greater than the current stack pointer... but I'm no expert.

Do you guys thing this is a valid approach for the OP to take?

Share this post


Link to post
Share on other sites
Quote:
Original post by Ravyne
I think he's wanting to see if the instance of the class was allocated on the heap (via new, for instance), or whether it was allocated on the stack (passed by value, for instance)

Since you would only have 'this' be on the stack when inside a member function of a class that was passed by value to some function further up the call stack, and the stack grows downwards, I suppose you could check for stack allocation by seeing if 'this' is greater than the current stack pointer... but I'm no expert.

Do you guys thing this is a valid approach for the OP to take?

The OP mentioned that he already knew how to check if a "pointer being passed in" was on on the stack or heap, but again it wasn't really clear what they meant. I was going to suggest using GetProcessHeap() to get some information on the size and location of the heap and check against that, but it certainly isn't portable and probably not a good idea in general anyway.

Share this post


Link to post
Share on other sites
Quote:
Original post by Ravyne
I think he's wanting to see if the instance of the class was allocated on the heap (via new, for instance), or whether it was allocated on the stack (passed by value, for instance)
But why would you want to do that anyway?

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP
Is there a way to do this?

No. Consider this code:

struct MyClass {
void bar(void);
};

void foo(MyClass * ptr) {
// magic that determines if ptr was this or not
}

void MyClass::bar(void) {
foo(this);
}

void baz1(MyClass * f) {
f->bar();
}

void baz2(MyClass * f) {
foo(f);
}

int main(int, char **) {
MyClass m;
baz1(&m);
baz2(&m);
}

Basically, in order to do that, you'd need some way to determine in foo() if baz1() or baz2() had been called. However, with MSVC in release mode, (and adding stuff into foo() to make sure it doesn't get inlined) the assembly for baz1() looks like:

jmp ?foo@@YAXPAUMyClass@@@Z ; foo

and the assembly for baz2() looks like:

jmp ?foo@@YAXPAUMyClass@@@Z ; foo

With no difference in the generated code there's no way to determine which was called. Since the resulting code is just a jump, there's no stack frame to examine and, in fact, with redundant COMDAT folding, even the function addresses would be the same.

Share this post


Link to post
Share on other sites
Quote:
Original post by Atrix256
You can always check if this == 0

The only way for "this == 0" to ever be true is to rely on undefined behavior. The function will explode before the check for virtual functions, and may evaluate to false even when the object the function was called on was null.

Especially in the case of multiple and/or virtual inheritance.

No seriously:
#include <iostream>

struct foo1 {
int a;
void f1() { std::cout << (this==0) << std::endl; }
};

struct foo2 {
int b;
void f2() { std::cout << (this==0) << std::endl; }
};

struct bar : foo1, foo2 {
int c;
void b1() { std::cout << (this==0) << std::endl; }
};

int main() {
bar* c = 0;
c->f1();
c->f2();
c->b1();
}






1
0
1
Press any key to continue . . . _


Results from both debug and release builds of a standard Win32 Console Project in MSVC2008 Professional. Remember kids: Friends don't let friends rely on undefined behavior!

[Edited by - MaulingMonkey on September 8, 2009 8:30:40 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP
Is there a way that I can check if the 'this' keyword was passed into a class


"The 'this' keyword" isn't a "thing" that can be passed. It's a way of obtaining a pointer to an object. (Also, "passed into a class" is nonsensical; you apparently mean "passed as a parameter to a constructor".)

There is no way to determine whether a pointer to an object was generated by code using the 'this' keyword or code not using the 'this' keyword, because either way, it's the same object, and thus, any pointers to the object are identical.

It almost seems like what you want is to enforce that the constructor is only called from member functions, and then check whether the passed-in value points to the object that initiated the call. But what do you think you could possibly accomplish by checking this, anyway? Show some code, so we can at least get closer to the question you really want to ask.

Quote:
I know how to check if a pointer being passed in is on the Stack or the Heap


No, you don't. Not in a standards-compliant, platform-agnostic way, anyway - because it doesn't exist. If you are doing it by checking address ranges (the only thing I can think of), it won't necessarily work on any other platform.

Quote:
but the 'this' keyword will always be on the Heap if the class itself was dynamically allocated.


Again, your terminology is sloppy. The 'this' keyword will yield a pointer to an object; and if that object was dynamically allocated, then the pointer will point to a heap location, because that's what "dynamically allocated" means. But this doesn't really have anything to do with what you're asking at all.

Quote:
Original post by MaulingMonkey
Quote:
Original post by Atrix256
You can always check if this == 0

The only way for this to ever be false...


I wonder if you realize that what you said could be interpreted as either exactly what you meant, or exactly the logical opposite :)

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
I wonder if you realize that what you said could be interpreted as either exactly what you meant, or exactly the logical opposite :)


That would explain why I originally wrote "... this to ever be true" before I 'corrected' it during editing <_<;

Share this post


Link to post
Share on other sites
Ok, whoa. I forget to check my post and a million people post.

Let me clarify. The way I check weather a pointer is on the Stack or Heap is by address range checking. I know it's architecture specific and It doesn't bother me (for now, anyways).

To be more specific, if someone passes a pointer into a smart pointer class, it will be reference counted and eventually deleted when the ref count reaches zero. However, if a smart pointer is used within a class and the 'this' pointer is passed into it, I would like it to somehow determine that it should not be deleted. My fall back is to manually specify the smart pointer to not delete the pointer when ref reaches zero.

So the point of my question was to determine if 'this' was passed into a function. If this is not possible then I can accept that - this is purely exploratory.

Share this post


Link to post
Share on other sites
Smart pointers are supposed to be smart about their business. They are not supposed to be NannyStatePointersThinkingOfTheChildren<T>.

As long as you accept only pointer and not reference semantics, it's impossible to point a pointer to stack object by mistake.

This question pops up every once in a while, but the basic conclusion is that it's not worth pursuing. Also, since smart pointers are effectively part of C++, their semantics should no longer be a mystery to anyone working in C++, so this isn't really needed.

Boost doesn't bother with it, and it doesn't seem to be any big problem.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
Smart pointers are supposed to be smart about their business. They are not supposed to be NannyStatePointersThinkingOfTheChildren<T>.


This is true, however I did add logic to determine if the pointer is Heap/Stack based in order to differentiate between:


Ptr<CFoo>; p = new CFoo();


and..

CFoo a;
Ptr<CFoo> p = &a;



So that when it runs out of scope it doesn't accidentally delete the stack based pointer. Tracking down an accidental delete of a Stack based value is a pain. But this is beside the point.

Quote:
As long as you accept only pointer and not reference semantics, it's impossible to point a pointer to stack object by mistake.


I don't accept references to objects, only pointers.

Quote:
This question pops up every once in a while, but the basic conclusion is that it's not worth pursuing. Also, since smart pointers are effectively part of C++, their semantics should no longer be a mystery to anyone working in C++, so this isn't really needed.


I did some more googling on this topic and with little results. I doubt there is a way to make this work. I will stick with my original way of disabling auto deletion.


Ptr<CFoo> p = this;
p.deleteOnZeroRef(false);




Quote:
Boost doesn't bother with it, and it doesn't seem to be any big problem.

This is true. One other option is to have a derived class that should only be used with the 'this' pointer.


ThisPtr<CFoo> p = this; // Automatically turns off deletion when reference reaches zero.

Share this post


Link to post
Share on other sites
Another problem with such a smart pointer is that you might easily end up holding a pointer to an object that has gone out of scope. Smart pointers are normally there to control the lifetime of an object, but you don't have such control over stack-based variables.

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP
To be more specific, if someone passes a pointer into a smart pointer class, it will be reference counted and eventually deleted when the ref count reaches zero. However, if a smart pointer is used within a class and the 'this' pointer is passed into it, I would like it to somehow determine that it should not be deleted.

Meh. Don't bother. If you try to make safe bad coding habits, you just encourage the use of bad coding habits. It's a mistake to construct a reference counted smart pointer from a stack object.

Share this post


Link to post
Share on other sites
Quote:
Original post by SiCrane
Quote:
Original post by RealMarkP
To be more specific, if someone passes a pointer into a smart pointer class, it will be reference counted and eventually deleted when the ref count reaches zero. However, if a smart pointer is used within a class and the 'this' pointer is passed into it, I would like it to somehow determine that it should not be deleted.

Meh. Don't bother. If you try to make safe bad coding habits, you just encourage the use of bad coding habits. It's a mistake to construct a reference counted smart pointer from a stack object.

Perhaps you could issue a run-time warning if you could detect that someone is trying to do that. That would be a more interesting application of what he is asking (not that I have seen a clear formulation of what the question in this thread really is).

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP

So that when it runs out of scope it doesn't accidentally delete the stack based pointer. Tracking down an accidental delete of a Stack based value is a pain. But this is beside the point.


Yes, there are many ways to break smart pointers.

People who make such *mistakes* should be using managed languages. People who deliberately abuse such functionality, better know what they are doing.

Here is a counter point:
Ptr<Foo> ptr;
Foo onStack;
*((Foo*)(((char*)(&ptr))+4)) = &onStack; // let's use the stack pointer
*((int*)(((char*)(&ptr))+8)) = 9999; // let's rev up the ref count so it doesn't get deleted


In C++, it is impossible to protect against abuse.

Share this post


Link to post
Share on other sites
Quote:
Original post by RealMarkP
So that when it runs out of scope it doesn't accidentally delete the stack based pointer.
Constructing a shared pointer to a stack object is a mistake, going out of your way to make it work implies that it's not a mistake. If you're still worried about this for some reason then better to make it emit a compile-time warning or even throwing an exception would do.

Rarely, but sometimes, the user might actually want to create a smart pointer to a stack allocated object. Boost's shared_ptr handles this by allowing them to specify a custom deleter:

foo f;
boost::shared_ptr<foo> p(&f, null_deleter());


This essentially makes the smart pointer dumb, when the reference count reaches zero nothing happens.

It also solves your smart pointer to this problem.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
In C++, it is impossible to protect against abuse, as in most programming languages.


text in italics added by me.

Program to pump free core memory, useful for gamers
void Main () {
try {
var l = new List<int>();
while (true)
l.Add (666);
foreach (var i in l) // arbitrary dependency so l is not optimized away
Console.WriteLine (i);
} catch {
Console.WriteLine ("it's free now!");
}
}

Share this post


Link to post
Share on other sites
Behold the power of C++0x:


#include <string>

template <class T>
class SmartPtr
{
T* ptr;
public:
template <class ...Args>
SmartPtr(Args&&... args): ptr(new T(std::forward<Args...>(args...))) {}
//...
};

int main()
{
SmartPtr<std::string> sp("Hello world");
}



If the best practice with smart pointers is to pass the result of new directly to the smart pointer's constructor, now one can pass the arguments and the smart pointer can allocate the object itself.

Share this post


Link to post
Share on other sites
Quote:
Original post by phresnel

text in italics added by me.


How do you break garbage collectors of managed languages using language only? Obviously, one can directly access the process memory, and when dropping to native part it's possible to make a mess, but still.

C and C++ however are mainstream languages in wide use, where it's trivial and deliberately allowed to do so.

Share this post


Link to post
Share on other sites
Quote:
Original post by Antheus
Quote:
Original post by phresnel

text in italics added by me.


How do you break garbage collectors of managed languages using language only? Obviously, one can directly access the process memory, and when dropping to native part it's possible to make a mess, but still.

C and C++ however are mainstream languages in wide use, where it's trivial and deliberately allowed to do so.


Yes. But you've written
Quote:
In C++, it is impossible to protect against abuse
and not
Quote:
In C++, it is impossible to protect against such abuse
.

Share this post


Link to post
Share on other sites
Quote:
Original post by visitor
Behold the power of C++0x:

*** Source Snippet Removed ***

If the best practice with smart pointers is to pass the result of new directly to the smart pointer's constructor, now one can pass the arguments and the smart pointer can allocate the object itself.


That's damn sexy.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this