Archived

This topic is now archived and is closed to further replies.

C++ "this" pointer?

This topic is 5697 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

In the process of writing a Texture manager class, I came across a peculiar bug: a this pointer that is NULL. I was wondering if anyone else has come across this, and knows under what circumstances a this pointer can be null. Also, as a bonus question to any more experienced programmers: When dealing with pointers/references passed between functions, where does the responsibility of testing the pointers for validity lie? Should the calling function test a pointer it is going to pass for NULL? Should the recieving function perform this chore? Or should this test (and/or assert()) be done in both? Thanks in advance, Patrick "a riddle wrapped in a mystery inside an enigma" - Churchill

Share this post


Link to post
Share on other sites
quote:
Original post by pdugan
In the process of writing a Texture manager class, I came across a peculiar bug: a this pointer that is NULL. I was wondering if anyone else has come across this, and knows under what circumstances a this pointer can be null.


It is my understanding that the "this" pointer refers to the active object's scope. If the active object has not been "newed" then "this" may be null. But don't take my word on that.
quote:

Also, as a bonus question to any more experienced programmers: When dealing with pointers/references passed between functions, where does the responsibility of testing the pointers for validity lie? Should the calling function test a pointer it is going to pass for NULL? Should the recieving function perform this chore? Or should this test (and/or assert()) be done in both?


In practice, I have seen that the receiving function is responsible for validating parameters. I am not quite sure the reasoning behind it, but it seems to be an accepted practice.



-----------------------------
kevin@mayday-anime.com
http://games.mayday-anime.com

-- edit: spelling

[edited by - grasshopa55 on May 2, 2002 4:51:10 PM]

Share this post


Link to post
Share on other sites
if this is NULL then the object has not been created properly.

now, about validating parameters.... it''s really a performance/stability issue. if you have a small function that going to be called thousands of times in your render loop. (for example, let''s say glVertex4fv ). there is no way you want glVertex4fv constantly calling IsBadReadPtr to validate the pointer, in your render loop. so glVertex4fv would be documented that it expects as a precondition that the pointer passed to it, be a valid readable pointer of 16 bytes (4 floats) in size. the opposite holds in reverse, i.e. a function like GetDC probably checks that the handle passed to it, is a valid window handle, because it''s not a time critical function.

To the vast majority of mankind, nothing is more agreeable than to escape the need for mental exertion... To most people, nothing is more troublesome than the effort of thinking.

Share this post


Link to post
Share on other sites
quote:
Original post by pdugan
In the process of writing a Texture manager class, I came across a peculiar bug: a this pointer that is NULL. I was wondering if anyone else has come across this, and knows under what circumstances a this pointer can be null.

this can never be NULL under any legal circumstances. An example of undefined behaviour under MSVC++6 which produces this effect is as follows:

    
#include <iostream>

using namespace std;

struct A
{
void f()
{
if(this)
cout << "OK" << endl;
}
};

int main()
{
A *pa = 0;
pa->f();
}


Despite the fact that this appears to work under MS, do not be fooled. It is strictly *undefined behaviour*, yet I've seen programmers do this in production code, and I believe there are instances of this code in MFC. It is illegal to dereference a NULL pointer, which is what operator-> does.
quote:

Also, as a bonus question to any more experienced programmers:

Oh, it's a quiz now, is it?
quote:

When dealing with pointers/references passed between functions, where does the responsibility of testing the pointers for validity lie?

A reference *must* be bound to an object, so it is again illegal to have a situation which results in anything other than that. That said, it should be apparent that you prefer references to pointers when there has to be a referent. So, you should be left with the situation where it is semantically valid to pass a NULL pointer into a function, leaving the responsibility for checking the pointer firmly with the function. There are exceptions, so use this is a rule of thumb.


[ C++ FAQ Lite | ACCU | Boost | Python | Agile Manifesto! ]

[edited by - SabreMan on May 2, 2002 5:46:42 PM]

Share this post


Link to post
Share on other sites
one possible cause of a NULL this pointer is an invalid type cast of a pointer. the member function you are calling doesn''t exist on the class you cast but because of your typecast the compiler allows it without errors.

Share this post


Link to post
Share on other sites
Another time you will see a null ''this'' pointer is when two threads are accessing an object and the object gets deleted by one of them. If one thread deletes the object while the second thread is executing in a member function, the object will no longer exist and the ''this'' pointer will be invalid; sometimes it will be NULL and other times it will be a wild pointer.


Dire Wolf
www.digitalfiends.com

Share this post


Link to post
Share on other sites
Wow, thank you everyone for the prompt reply; I was not expecting such punctual assistance.

Sabreman, your code sample was spot on. This is precisely the behaviour I am experiencing: ''if (this)'' will let the program run successfully, but ''assert (this)'' throws an error.

I''m currently looking into changing how my TextureManager class (and other classes) are instantiated (ie: not using direct pointers and ''new'').

The object arrangement I have currently is an Engine class using the facade design pattern (see Design Patterns, GOF). A LoadPlugins(...) method new''s the Engine''s pointers corresponding to the correct plugins. Now, if I was loading the plugins using the Engine class''s constructor, I would simply represent the plugin objects as references and be done with it. However, I would like to defer loading of the plugins as the Engine constructor requires some setup parameters (and I''d like to break the interface down to be as simple as possible). I also don''t want to statically declare the plugins in the Engine class, as I want the user to be able to load only the features they need to reduce the memory/processing footprint.

Btw, if there''s any interest in looking at my code, I''d be happy to put it on my website, and/or setup a CVS server.

Thanks again for all your help, and I hope I''m not pushing my luck with another question.

"a riddle wrapped in a mystery inside an enigma" - Churchill

Share this post


Link to post
Share on other sites
The major recommendation I''d make for pointer management is to familiarise yourself with various smart pointers. Check out the Boost website (see my sig) where you can freely download their libraries. There''s a *lot* of really useful stuff, and their shared_ptr is a glaring omission from the Standard Library.

I hope I got my message across about the NULL "this" pointer. In my code, where I am saying if(this), that in itself is OK. What''s not OK is that you would even get as far as calling the function with a NULL this pointer, since it''s illegal to dereference a NULL pointer. Therefore, the if(this) check is futile, because the code has already invoked undefined behaviour and you cannot rely on anything. You might get seemingly reasonable results on MS''s compiler, but the C++ Standard makes no guarantees, and I''m not sure even MS''s compiler behaves in the same way when multiple inheritance is involved.


[ C++ FAQ Lite | ACCU | Boost | Python | Agile Manifesto! ]

Share this post


Link to post
Share on other sites
since it is possible to call methods of a class - class::method() - without refering to an instance of the class, then it''s very possible to have a null ''this''.

one implementation of the singleton pattern makes use of calling a function on a non existant object - Singleton::Instance()

if all your functions are non pure, all data static then you don''t really need an instance of the class. it''s pretty unusual though and best avoided - unless it''s a well documented and understood use.

actually, i guess a texture manager class would be a prime candidate for the singleton pattern, so maybe that''s what you are witnessing.

Share this post


Link to post
Share on other sites
quote:
Original post by petewood
since it is possible to call methods of a class - class::method() - without refering to an instance of the class, then it's very possible to have a null 'this'.

Not without invoking illegal (undefined) behaviour. There are *no* exceptions.
quote:

one implementation of the singleton pattern makes use of calling a function on a non existant object - Singleton::Instance()

That would require Instance() to be a static member function. Static members do not have a 'this' pointer.
quote:

if all your functions are non pure, all data static then you don't really need an instance of the class. it's pretty unusual though and best avoided - unless it's a well documented and understood use.

It's completely illegal!


[ C++ FAQ Lite | ACCU | Boost | Python | Agile Manifesto! ]

[edited by - SabreMan on May 4, 2002 8:08:56 AM]

Share this post


Link to post
Share on other sites
static member functions - that''s right - i should have been clearer.

why is it completely illegal? does it say in the standard? it''s in alexandrescus loki library and a number of other implementations of the singleton pattern including scott meyers version.

i''d like to know if it''s just abhorant because it''s unusual and could cause problems if not well understood or because bjarne says so

Share this post


Link to post
Share on other sites
quote:
Original post by petewood
why is it completely illegal? does it say in the standard?

The Standard makes it quite clear that it is illegal to dereference a NULL pointer, which is what is required to be able to call a function through that pointer. All behaviour from dereferencing onwards is undefined.
quote:

it''s in alexandrescus loki library and a number of other implementations of the singleton pattern including scott meyers version.

What is? I think you are confused. You can call a static member function without a class instance, since static means that there is no ''this'' pointer. That''s what Alexandrescu and Meyers use. That has nothing to do with a NULL this pointer, as there is no this pointer whatsoever.
quote:

i''d like to know if it''s just abhorant because it''s unusual and could cause problems if not well understood or because bjarne says so

It''s illegal because the Standard says so.


[ C++ FAQ Lite | ACCU | Boost | Python | Agile Manifesto! ]

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
The Standard makes it quite clear that it is illegal to dereference a NULL pointer, which is what is required to be able to call a function through that pointer. All behaviour from dereferencing onwards is undefined.


But why do you need to dereference anything when calling a nonvirtual method?


Share this post


Link to post
Share on other sites
quote:

The Standard makes it quite clear that it is illegal to dereference a NULL pointer, which is what is required to be able to call a function through that pointer.

Not normally it isn''t, no.

Normally, C++ member functions are regular functions taking a pointer to the class type (i.e. a pointer to a struct containing the member variables) as their first parameter. If you never access any member variables, you won''t ever dereference the pointer.

This isn''t a language requirement, it''s an ABI requirement, so it should be consistent at least within a given hardware + OS combination.

Share this post


Link to post
Share on other sites
I use a null this pointer in my code, but I''ll probably rewrite it so I won''t have to. Still, it works perfectly.

Basically, I have a renderer class, from which is derived opengl and direct3d. To switch between the two, I say:

renderer* Renderer = new direct3d;
// later, switch to opengl:
delete Renderer;
Renderer = new opengl;

The renderer base class has static members that are shared between the two APIs. It also has data that needs to be destroyed when the app quits, so I call renderer::Destroy(). But that function also tests to see if this is NULL, and if not, then it calls the virtual function to free all API-specific data.

The reason it could be better is that either I can delete the renderer before calling Destroy(), and then make Destroy static, or I can use an additional class that contains a renderer object, which holds the static data instead of the renderer class, and which handles creation/destruction of the API classes.

~CGameProgrammer( );

Share this post


Link to post
Share on other sites
sabreman was saying "it''s completely illegal" when i was talking about calling static member functions but he only meant dereferencing null this pointers. that''s what confused me. so he was confused and i was confused.

cross porpoises

Share this post


Link to post
Share on other sites
I have been browsing through the standard and what I have found is that calling a member function through a NULL pointer is as compiler dependent as the implementation of virtual functions.

The standard does not say that the compilation of obj->member() turns into class::member( obj ); If they did had defined it, then could you could use a member function pointer like this :

class T
{

};

typedef void(T::*MEMBERFUNC)(void);

MEMBERFUNC func;
T obj;

(*func)( &obj );

But you cannot, C++ defines 2 operators to do this. ->* and .*.


The only thing that the standard says is that there is a non lvalue variable called "this", that points to the object from which the method has been called, that is defined in all member functions.

In conclusion it is not illegal, but you are going into the realm of undefined behavior and it is obviously something that should be avoided.

[edited by - Gorg on May 5, 2002 2:08:49 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by DrPizza
Not normally it isn't, no.

Not normally what isn't? Are you trying to say that you don't have to dereference a pointer to call a method through a pointer to object? If so, you are wrong.
quote:

Normally, C++ member functions are regular functions taking a pointer to the class type (i.e. a pointer to a struct containing the member variables) as their first parameter. If you never access any member variables, you won't ever dereference the pointer.

So how does the program call a method on a particular instance if it never dereferences the pointer? Remember, the syntax:

object->func();

is the same as:

(*object).func();

(you can confirm that in 5.2.5 para 3 of the Standard if you consider me too unreliable).

Just in case you are confused, the '*' syntax is a pointer dereference.

quote:

This isn't a language requirement, it's an ABI requirement, so it should be consistent at least within a given hardware + OS combination.

Huh? Are you saying there is some ABI requirement that supercedes the rules that the C++ Standard imposes? I don't think so.

quote:
Original post by petewood
sabreman was saying "it's completely illegal" when i was talking about calling static member functions but he only meant dereferencing null this pointers. that's what confused me. so he was confused and i was confused.

I have never been confused during this thread. Let me just remind you what you said:

"since it is possible to call methods of a class - class::method() - without refering to an instance of the class, then it's very possible to have a null 'this'."

Yes, it's possible to have a NULL 'this', but it's not legal. Since you mentioned Singleton, I pointed out that Singleton requires a static member function, which does not have a 'this' pointer. That was a distraction to the main point.


[ C++ FAQ Lite | ACCU | Boost | Python | Agile Manifesto! ]

[edited by - SabreMan on May 5, 2002 7:07:25 AM]

[edited by - SabreMan on May 5, 2002 7:47:24 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
So how does the program call a method on a particular instance if it never dereferences the pointer?

Like I said. Most ABIs turn class member functions into functions that like mangledName(classType* this, remaining parameters), where classType is the type of the class that the member works on. The actual in-memory representation of the class is just its data members.

quote:
Remember, the syntax:
object->func();
is the same as:
(*object).func();
(you can confirm that in 5.2.5 para 3 of the Standard if you consider me too unreliable).
Just in case you are confused, the ''*'' syntax is a pointer dereference.

Can you show me one compiler or ABI that works like that? Win32''s ABI doesn''t, gcc/g++''s ABI doesn''t work like that, Itanium''s ABI doesn''t work like that.

For static lookups, there is no need to dereference the pointer, and compilers won''t bother to dereference the pointer.

quote:
Huh? Are you saying there is some ABI requirement that supercedes the rules that the C++ Standard imposes? I don''t think so.

Of course they do, unless you don''t bother ever compiling or running any code and so can live in the fantasy land of the C++ standard. The ABIs in current use require member functions to work in a particular way; the way they work is one that doesn''t require the ''this'' pointer to ever be dereferenced. The language may say "this is a dereference", but no compiler or ABI will treat it as such, with good reason -- it''s nonsense; for static function calls, at least, there is no reason to dereference anything, and nothing good will come of it.

Things change for dynamic lookups, as the thing will have to find the v-table somewhere, but the example given didn''t require a dynamic function lookup.

Share this post


Link to post
Share on other sites
quote:
Original post by DrPizza
Can you show me one compiler or ABI that works like that? Win32's ABI doesn't, gcc/g++'s ABI doesn't work like that, Itanium's ABI doesn't work like that.

Compilers do not define the language Standard. I strongly suggest you stop taking the inner workings of your compiler to define the operation of C++. The fact that many compilers will perform in this manner does not in any way violate the meaning of undefined behaviour. Each time you unnecessarily rely on undefined behaviour, you are making a programming mistake.
quote:

Of course they do, unless you don't bother ever compiling or running any code and so can live in the fantasy land of the C++ standard.

So the C++ Standard is a fantasy? I think I can see where your argument derives from.
quote:

The ABIs in current use require member functions to work in a particular way; the way they work is one that doesn't require the 'this' pointer to ever be dereferenced.

ABIs do not define the C++ language. The C++ Standard does. If you are happy to disregard the C++ Standard, then there is little point us having this discussion.


[ C++ FAQ Lite | ACCU | Boost | Python | Agile Manifesto! ]

Edit: typo.

[edited by - SabreMan on May 5, 2002 8:12:31 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
[quote]Original post by Gorg
In conclusion it is not illegal, but you are going into the realm of undefined behavior and it is obviously something that should be avoided.

Undefined behaviour is a specialised form of illegal behaviour.


[ C++ FAQ Lite | ACCU | Boost | Python | Agile Manifesto! ]

ugh... I will argue over semantics details, but I can''t stop myself from typing

I don''t think illegal behavior exists. Illegal constructs do.

obj* t = NULL;

t.Func(); //is an illegal construct

t->Func() ; //is a legal construct that leads to undefined behavior by the standard.


I did not put much thought into it, but I cannot think of a place where the standard says, this thing leads to illegal behavior.

Behavior is simply defined or it is not.

Constructs are legal or not.

Share this post


Link to post
Share on other sites
Yes, you''re right that "illegal behaviour" is a poor term. What I was trying to say is that undefined behaviour is generally regarded as illegal by the C++ community, so it would be quite natural to say something like "it''s illegal to dereference a NULL pointer".


[ C++ FAQ Lite | ACCU | Boost | Python | Agile Manifesto! ]

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
Yes, you''re right that "illegal behaviour" is a poor term. What I was trying to say is that undefined behaviour is generally regarded as illegal by the C++ community, so it would be quite natural to say something like "it''s illegal to dereference a NULL pointer".


[ C++ FAQ Lite | ACCU | Boost | Python | Agile Manifesto! ]


Agree. Like I said, I just could not stop myself from typing

Share this post


Link to post
Share on other sites
quote:
Original post by SabreMan
Compilers do not define the language Standard.

The language standard doesn''t produce executable code, either. The language standard only governs the syntax of the language. Real world constraints have a great deal of impact on how the language works too.

quote:
I strongly suggest you stop taking the inner workings of your compiler to define the operation of C++.

Again, if you''re happy to live in a fantasy world where you never have to generate any executable binaries from your code, it''s quite alright to witter on about the C++ standard.

I don''t think most of us have that luxury. ABIs necessarily have precendence over the standard. And ABIs state that staticly calling a class method on a null pointer won''t dereference that pointer unless/until an attempt is made to access any member variables. In spite of what the C++ Standard says on the issue, things don''t (and won''t) work in the manner it describes.

In any case -- the ABI requirements probably fall under the "as-if" rule.

quote:
So the C++ Standard is a fantasy? I think I can see where your argument derives from.

No, but what it describes is. It states explicitly that implementations need not operate in the same way as the abstract machine described by the standard, only that they have the same observable behaviour.

quote:
ABIs do not define the C++ language. The C++ Standard does.

But the C++ Standard also permits implementations to subvert the standard if the semantics fit. Neglecting to dereference pointers in this way is such a subversion.

quote:
If you are happy to disregard the C++ Standard, then there is little point us having this discussion.

The C++ Standard is irrelevant. You can''t use the C++ Standard to write or compile programs. It doesn''t even tell you enough to be able to generate a functional compiler (the best it can manage is a parser). I don''t know about you, but I want actual compiled exectuables from my code. And the rules governing those executables have far more impact than whatever the C++ Standard may or may not say. And those rules state, amongst other things, that the this pointer is explicitly passed as the first argument to any method. The act of staticly calling a method does not dereference any pointers, nor will it ever, because despite what the C++ Standard says, methods are not members of a class. They''re plain functions that implicitly take an extra parameter that the C++ Standard calls this.

You can talk about the standard all you like, but does it tell you how your code works? No, and it never will. It provides some rules on the syntax of a language, that''s all. Constraints and requirements of ABIs will always take precedence over those rules.

Share this post


Link to post
Share on other sites