This question already has answers here:
Is it legal C++ to test the this-pointer in a member function?
(5 answers)
Closed 6 years ago.
So i'm aware that this is a reference to the class itself, however I can't really tell what it does in an if statement
What does the following code do?
if(this)
{
//Code goes here...
}
I'm fairly sure it is checking if the class is not null, but a further explanation would be great!
this pointer is a constant pointer that holds the memory address of the current object. So, technically this will check whether it is null or not which will not be null in member function. Since you will not be able to call a class until you have its object and in abstract classes you can't use this anyway. So, this if doesn't make much sense.
It's attempting to check to see if the method was called on a NULL pointer, e.g. something like this:
Foo * foo = NULL;
foo->TheMethod();
However, that isn't a valid technique, since calling a method (even a non-virtual method!) on a NULL pointer is undefined behavior and so the test won't work reliably.
It is indeed checking if this != nullptr. However by the time you reach this statement, you have already passed from undefined behavior. Because this is available only in a class method and calling such method with nullptr is UB.
Hence such statement never serves any valid purpose.
Besides UB, also remember that such checks are useful only when called with a pointer. They are irrelevant for object/reference. If the method is virtual then most of the architecture would crash the code before reaching that if.
Related
This question already has answers here:
When does invoking a member function on a null instance result in undefined behavior?
(2 answers)
Closed 1 year ago.
I was given the following as an interview question:
class A
{
public:
void fun()
{
std::cout << "fun" << std::endl;
}
};
A* a = NULL;
a->fun();
What will happen when this code is executed, and why?
See also:
When does invoking a member function on a null instance result in undefined behavior?
It's undefined behavior, so anything might happen.
A possible result would be that it just prints "fun" since the method doesn't access any member variables of the object it is called on (the memory where the object supposedly lives doesn't need to be accessed, so access violations don't necessarily occur).
By the standard, this is undefined behavior and therefore a very bad thing. In reality of most programming platforms (across both X86 and several other architectures) this will run fine.
Why? Consider how class functions are implemented in C++. This isn't a virtual function, therefor this can be a static call to a known address.
In x86 assembly, we can see this as
mov A, 0
mov ecx, A
call a__fun
since a__fun requires no instance data, even though it receives a null this pointer, nothing will happen.
Still shitty code and any compiler will scream, but it can run.
The most likely behavior, on most modern computers, is that it will run, and print "fun", because:
C++ doesn't check whether the pointer is NULL before calling the function
fun() is not virtual, so there's no need to refer to a vtable to call fun()
fun() never access any member variables in A so it doesn't need to dereference
the null this pointer.
We can't know what will. Everything can happen, because the program exposes undefined behavior. See Does invoking a member function on a null instance cause undefined behavior?.
I have tried multiple times,all the time output is coming "fun" this is because function fun is independent of instance a. while calling a->fun(); a points to 0 so this is undefined behavior but in most of the compilers there should be no crash.
Three points might help:
1) All Functions are stored in code or text section.
2) Non Virtual functions are resolved at complie time.
3) While calling to member functions of class, we pass current object as this pointer to that function.
Coming to your question , here fun() function is already in memory(code section / text section).
As function fun() is non virtual , it will be resolved at complie time (i.e, for this line it will jump to instruction X at code section with this pointer as NULL).
As no member variable and no virtual function are used/called in fun() function, it is working fine.
In my early days with C++, I seem to recall you could call a member function with a NULL pointer, and check for that in the member function:
class Thing {public: void x();}
void Thing::x()
{ if (this == NULL) return; //nothing to do
...do stuff...
}
Thing* p = NULL; //nullptr these days, of course
p->x(); //no crash
Doing this may seem silly, but it was absolutely wonderful when writing recursive functions to traverse data structures, where navigating could easily run into the blind alley of a NULL; navigation functions could do a single check for NULL at the top and then blithely call themselves to try to navigate deeper without littering the code with additional checks.
According to g++ at least, the freedom (if it ever existed) has been revoked. The compiler warns about it, and if compiling optimized, it causes crashes.
Question 1: does the C++ standard (any flavor) disallow a NULL this? Or is g++ just getting in my face?
Question 2. More philosophically, why? 'this' is just another pointer. The glory of pointers is that they can be nullptr, and that's a useful condition.
I know I can get around this by making static functions, passing as first parameter a pointer to the data structure (hellllo Days of C) and then check the pointer. I'm just surprised I'd need to.
Edit: To upvote an answer I'd like to see chapter and verse from the standard on why this is disallowed. Note that my example at NO POINT dereferences NULL. Nothing is virtual here, and p is copied to "argument this" but then checked before use. No defererence occurs! so dereference of NULL can't be used as a claim of UB.
People are making a knee-jerk reaction to *p and assuming it isn't valid if p is NULL. But it is, and the evidence is here:
http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232
In fact it calls out two cases when a pointer, p, is surprisingly valid as *p: when p is null or when p points one element past the end of an array. What you must never do is USE the value of *p... other than to take the address of it. &*p where p == nullptr for any pointer type p IS valid. It's fine to point out that p->x() is really (*p).x(), but at the end of the day that translates to x(&*p) and that is perfectly well formed and valid. For p=nullptr... it simply becomes x(nullptr).
I think my debate should be with the standards community; in their haste to undercut the concept of a null reference, they left wording unclear. Since no one here has demanded p->x() is UB without trying to demand that it's UB because *p is UB; and because *p is definitely not UB because no aspect of x() uses the referenced value, I'm going to put this down to g++ overreaching on a standard ambiguity. The absolutely identical mechanism using a static function and extra parameter is well defined, so it's not like it stops my refactor effort. Consider the question withdrawn; portable code can't assume this==nullptr will work but there's a portable solution available, so in the end it doesn't matter.
To be in a situation where this is nullptr implies you called a non-static member function without using a valid instance such as with a pointer set to nullptr. Since this is forbidden, to obtain a null this you must already be in undefined behavior. In other words, this is never nullptr unless you have undefined behavior. Due to the nature of undefined behavior, you can simplify the statement to simply be "this is never nullptr" since no rule needs to be upheld in the presence of undefined behavior.
Question 1: does the C++ standard (any flavor) disallow a NULL this?
Or is g++ just getting in my face?
The C++ standard disallows it -- calling a method on a NULL pointer is officially 'undefined behavior' and you must avoid doing it or you will get bit. In particular, optimizers will assume that the this-pointer is non-NULL when making optimizations, leading to strange/unexpected behaviors at runtime (I know this from experience :))
Question 2. More philosophically, why? 'this' is just another pointer.
The glory of pointers is that they can be nullptr, and that's a useful
condition.
I'm not sure it matters, really; it's what is specified in the C++ standard, and they probably had their reasons (philosophical or otherwise), but since the standard specifies it, the compilers expect it, therefore as programmers we have to abide by it, or face undefined behavior. (One can imagine an alternate universe where NULL this-pointers are allowed, but we don't live there)
The question has already been answered - it is undefined behavior to dereference a null pointer, and using *obj or obj-> are both dereferencing.
Now (since I assume you have a question on how to work around this) the solution is to use static function:
class Foo {
static auto bar_st(Foo* foo) { if (foo) return foo->bar(); }
}
Having said that, I do think that gcc's decision of eliminating all branches for nullptr this was not a wise one. Nobody gained by that, and a lot of people suffered. What's the benefit?
C++ does not allow calling member functions of null object. Objects need identity and that can not be stored to null pointer. What would happen if member function would read or write a field of a object referenced by null pointer?
It sounds like you could use null object pattern in your code to create wanted result.
Null pointer is recognised a problematic entity in object oriented languages because in most languages it is not a object. This creates a need for code that specifically handles the case something being null. While checking for special null pointer is the norm. There are other approaches. Smalltalk actually has a NullObject which has methods its own methods. As all objects it can also be extended. Go programming language does allow calling struct member functions for something that is nil (which sounds like something required in the question).
this might be null too if you delete this (which is possible but not recommended)
This question already has answers here:
Is "delete this" allowed in C++?
(10 answers)
Closed 7 years ago.
Suppose I have a class foo with a function release that calls delete this:
struct foo
{
std::int32_t release() const
{
delete this;
return 0;
}
};
Why can I even call delete this given that the function is const?
Is the behaviour on returning 0 defined? Doesn't the function "sort-of-die" after the delete?
An answer referencing the standard (so I can put a fancy comment in my code) would be much appreciated.
Why can I even call delete this given that the function is const?
From the standard, 5.3.5$2 Delete [expr.delete]
[ Note: a pointer to a const type can be the operand of a
delete-expression; it is not necessary to cast away the constness
(5.2.11) of the pointer expression before it is used as the operand of
the delete-expression. —end note ]
and
Is the behaviour on returning 0 defined?
I think it's safe. delete this; will call the destructor and free the memory hold by the object (including the member variables and base class subobject). After that, if you don't derefrence this, or access any member variables, it'll be safe.
Why can I even call delete this given that the function is const
Because delete doesn't necessarily modify the deleted pointer.
Is the behaviour on returning 0 defined? Doesn't the function "sort-of-die" after the delete?
Why would it? The logic isn't removed from the program. The functionality stays in memory for next objects to use it. It's only this pointer that gets invalidated.
There's an SO answer that points to The ISO C++ FAQ which has an entry on that, excerpts of which:
You must be absolutely 100% positively sure that the rest of your member function (after the delete this line) doesn’t touch any piece of this object (including calling any other member functions or touching any data members). This includes code that will run in destructors for any objects allocated on the stack that are still alive.
You must be absolutely 100% positively sure that no one even touches the this pointer itself after the delete this line. In other words, you must not examine it, compare it with another pointer, compare it with nullptr, print it, cast it, do anything with it.
Since your code abides those rules, again, it's fine.
This question already has answers here:
What will happen when I call a member function on a NULL object pointer? [duplicate]
(6 answers)
Closed 8 years ago.
How does it work?
QDesktopWidget *Desktop=NULL;
auto Desktop_Rect=Desktop->screenGeometry();
pDebug()<<Desktop_Rect.width()<<","<<Desktop_Rect.height(); //1440,900
If I rewrite it as following:
auto Desktop_Rect=QDesktopWidget::screenGeometry();//Error:screenGeometry is not a static method.
pDebug()<<Desktop_Rect.width()<<","<<Desktop_Rect.height();
Basically your question has less to do with Qt but with C++.
The pointer isn't required to call the method, but the type of the pointer.
The method might not use this, so it runs the code just fine.
The bahaviour should be undefined, depends on the implementation of screenGeometry method.
P.S. Compile with warnings AND DON'T IGNORE THEM (suggested by Jeoren in comments)
This works in all cases where you call a class method on a NULL-pointer. The compiler does not (cannot) check for valid values of the pointer at compile time. It only looks at the type of the pointer, and as long as that checks out (in this case, the QDesktopWidget class does indeed have a function called screengGeometry that accepts 0 parameters) it will happily compile your code.
However, at runtime, this will most likely crash as soon as the code in that function accesses the class's data members. That is when it tries to dereference the "this" pointer, which in this case is NULL. The fact that your first example runs successfully simply means it does not access instance data, but only static or global data.
The second snippet is simply a completely different case, where you are trying to call a method as if it was static, while it is not. This results in the entirely correct and helpful error message you quote.
Ask yourself this though: What should the function return when you call screenGeometry when there is no instance to which it belongs. Both code snippets try to do something nonsensical.
This question already has answers here:
Is it legal/well-defined C++ to call a non-static method that doesn't access members through a null pointer?
(5 answers)
When does invoking a member function on a null instance result in undefined behavior?
(2 answers)
Closed 8 years ago.
Can I call a non-static, non-virtual method of a class from a null pointer? The member function would then test if this==nullptr, and return immediately if it's true.
I know it will work in most cases, but is this a guaranteed result? That way, I can ensure null pointer exceptions never happen, and avoid testing for null pointers in many places of the caller code. That's for compactness, I'm not going to do that right now, but I'm curious to know if any standard will guarantee this to work...
Thanks!
Dereferencing a nullptr is Undefined behavior. Period!
Whether it works or not on one particular implementation is irrelevant, the behavior is not guaranteed.
The standard expliticly mentions dereferencing NULL pointer as undefined behavior. Using opearator -> dereferences the pointer to left.
So you're okay only in case if your implementation defined some behavior for the case, as it is a possibility (though I never encountered it in real life yet).
(I hope you understand that observing something is not the same as being defined.)
always avoid calling a null pointer,
you would usually end up with a core dump
There are interesting answers here:
When does invoking a member function on a null instance result in undefined behavior?
Also, the standard gives no hint about the mechanism for calling member virtual functions. It is usually done by just passing 'this' as a hidden function argument, which will in practice not dereference the pointer and work. However, it seems possible to implement even non-virtual function with a vtable, which in this case would crash.
Interestingly, a Microsoft function relies on this behavior :)
http://msdn.microsoft.com/en-us/library/d64ehwhz%28v=vs.80%29.aspx