我想知道如果在每个成员函数上放置assert(this != nullptr);
是个好主意。我相信编译器可以决定完全忽略这个断言,因为它是假定this
不能为空,所以assert始终为真,并且可以在编译时解析。编译器是否假设在调试模式下“this”不是nullptr?
但是,如果编译器没有做出这个假设,那么这个断言对于及早发现问题非常有用。
编译器是否会这样做?
我想知道如果在每个成员函数上放置assert(this != nullptr);
是个好主意。我相信编译器可以决定完全忽略这个断言,因为它是假定this
不能为空,所以assert始终为真,并且可以在编译时解析。编译器是否假设在调试模式下“this”不是nullptr?
但是,如果编译器没有做出这个假设,那么这个断言对于及早发现问题非常有用。
编译器是否会这样做?
不,编译器通常不会这样假设。甚至有商业代码在进行这些检查,有些不仅仅是断言,而是实际上是逻辑。 if (!this) { doSomeWork(); }
。
虽然你不能达到this
将NULL
没有运行到未定义的行为的情况下,如果你很清楚实现的细节,那么这是你可以做的检查;是的,你说得对,可以帮助调试。
虽然我不会把它放在任何地方。任何地方,就此而言。如果this
确实是NULL
,那么稍后在访问某个成员时可能会崩溃。如果您未访问任何成员,请考虑标记方法static
。它也不必要地膨胀了代码。
编译器通常只在开启优化时采取任何操作。所以,如果你编译时没有进行优化(只要你没有定义NDEBUG
,那么assert
就被启用了,这与优化无关),assert将起作用。
它会遇到常规方法的问题,但请记住,对于虚拟方法,为了调用该方法而取消引用this
指针,因此在调用此检查之前已发生崩溃。对于大多数非虚方法来说,如果方法访问任何成员(如果没有,首先不应该成为实例成员函数),问题不会被忽视,因此添加断言是否有意义是个问题。
不,这不总是取消引用来打电话!在非虚拟调用的情况下,则不需要取消引用指针。 –
删除我的意见,与您的编辑它现在没有意义:) – qdii
不,只需要在非虚拟的非静态成员函数中声明它。
在静态成员上,this
被禁止,所以没问题。
在非虚拟的非静态成员,调用编译器静态地确定然后像ptr->f()
呼叫可以被翻译成类似f(ptr)
,所以你可以有一个空this
!奇怪但可能。所以你可以断言它。
在虚拟成员上,由于呼叫是动态计算的,因此这绝不会发生。要找到该函数,需要对指针取消引用(通过指针查阅vtable),这样机器就会在此时崩溃(取消引用空指针总是崩溃),就在您有机会进行有效调用之前。
实验与本:
#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
}
为什么负面的表示法?你应该评论... –
因为“在非虚拟的非静态成员上,由于调用是由编译器静态确定的,所以像ptr-> f()这样的调用可以被翻译成类似f(ptr)的东西,所以你可以有一个null!“这是不正确的。这不是有效的代码,它调用未定义的行为。 (当回答“为什么这个答案错误”时,评论是多余的)在其他答案中。) –
要除了那些已经说的是,它使不出来测试this
为nullptr
。即使指针确实是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;
}
如果它只能检测错误*有时*,我仍然会接受它。 – qdii
'struct foo {int bar; void baz(){bar = 1; }} * crash = 0; crash-> baz();'嘿presto,'this'为NULL。 –
@JonathanPotter是吗? :)我说'crash-> baz()'是未定义的行为,所以之后的任何事情都可能发生。 –
@JonathanPotter:嘿presto,“这个”已经被转化成了一块美味的奶酪。 –