我在想是否在每个成员函数中加入assert( this != nullptr );
是一个好主意。我认为编译器可以决定完全忽略此断言,因为假定this
不能为空指针,所以该断言始终为真并可在编译时解决。
但是如果编译器没有做出这种假设,则此断言非常有用,可以早期捕获问题。
编译器会做出这种假设吗?
我在想是否在每个成员函数中加入assert( this != nullptr );
是一个好主意。我认为编译器可以决定完全忽略此断言,因为假定this
不能为空指针,所以该断言始终为真并可在编译时解决。
但是如果编译器没有做出这种假设,则此断言非常有用,可以早期捕获问题。
编译器会做出这种假设吗?
if (!this) { doSomeWork(); }
。this
为 NULL
的情况而不陷入未定义的行为,但如果你对实现细节非常了解,那么这是一个可以进行的检查;而且,你是正确的,它确实可以帮助调试。this
确实是 NULL
,则在访问某些成员时您可能会稍后出现崩溃。如果您没有访问任何成员,请考虑将该方法标记为static
。它也会不必要地使代码膨胀。if (!this) doSomeWork();
有点惊讶,因为这是明显的未定义行为,你为什么会假设你的函数会被执行呢?下一个版本的编译器可能会忽略它。 - qdiiassert
会生效,只要你没有定义NDEBUG
,这与优化无关),那么assert
会生效。this
指针才能调用函数,在这个检查被调用之前程序就已经崩溃了。对于大多数非虚函数,如果函数访问任何成员(如果不访问任何成员,则它本身就不应该是实例成员函数),问题将不会被忽略,因此是否添加assert
是一个值得考虑的问题。除了已经提到的内容,对于nullptr
来测试this
是没有意义的。即使指针确实是nullptr
,this
也不总是为零。以下是一个例子:
#include <iostream>
struct A
{
void foo() { std::cout << this << std::endl; }
int a;
};
struct B
{
void boo() { std::cout << this << std::endl; }
int b;
};
struct C: public A, public B
{
};
int main()
{
C *c = 0;
c->foo(); // this == 0
c->boo(); // this == 4
return 0;
}
不必在虚拟的静态成员函数上断言它。
对于静态成员,this
被禁止使用,所以没问题。
对于非虚拟的非静态成员,由于调用被编译器静态确定,因此像 ptr->f()
这样的调用可以被转换为类似 f(ptr)
的东西,因此你可以有一个空的 this
!奇怪但是可能的。所以你可以断言它。
对于虚拟成员,由于调用是动态计算的,这是不可能发生的。为了找到函数,需要通过指针解引用(通过指针查看虚函数表),所以机器将在那个时候崩溃(解引用空指针总是会崩溃),在你有任何机会进行有效调用之前。
尝试一下这个:
#include <iostream>
using namespace std;
struct foo {
int bar;
void baz() { bar = 1; }
void barf() { int i = 5; cout << "barf" << this << endl;}
virtual void barf2() { int i = 5; cout << "barf2" <<this << endl;}
};
int main() {
struct foo * crash = 0;
crash->barf(); // do not crash
crash->barf2(); // crash
//crash->baz(); // crash
}
crash->baz()
是未定义行为,因此之后的任何结果都有可能发生。 - Luchian Grigorethis
已经被转化成了一块美味的奶酪。 - Lightness Races in Orbit