On at least one compiler, yes, the check makes sense. It will work as you expect and it is possible to trigger it. Whether it’s useful is questionable, since well-formed code should never call a member function on a null pointer, but assert(this);
is cheap.
The following code will compile on MSVC 19.37 and run as expected. It will not issue a warning, even with /std:c++20 /Wall /external:anglebrackets /external:W0
.
#include <cstdlib>
#include <functional>
#include <iostream>
using std::cerr, std::cout;
class Foo {
public:
void sillyContrivance() const noexcept {
if (this) {
cout << "hello, world!\n";
} else {
cerr << "Null this pointer!\n";
}
}
};
int main() {
static_cast<Foo*>(nullptr)->sillyContrivance();
const auto closure = std::bind(&Foo::sillyContrivance, static_cast<Foo*>(nullptr));
closure();
}
The program prints Null this pointer!
twice.
Clang 16.0.0 will warn you that this
cannot be null, turn the check into a no-op, and print hello, world!
twice. GCC 13.2 will additionally warn you that you are calling a member function on a null pointer, and also print hello, world!
twice.
In real-world, practical use, a member function that never needs to dereference this
would have been declared static
, so realistic code compiled with Clang or GCC that triggers this bug (such as passing around a default-initialized struct
containing an object pointer) would segfault on modern OSes. However, the sanity check would be useless on compilers that optimize it away.
((Foo*)0)->foo()
is perfectly valid syntax. As long asfoo()
is not a virtual function, this will even work on most compilers, but it's just icky. – Widthwisethis
to become null in that other thread. – Musick