2014-02-12 20 views
5

我想知道如果在每个成员函数上放置assert(this != nullptr);是个好主意。我相信编译器可以决定完全忽略这个断言,因为它是假定this不能为空,所以assert始终为真,并且可以在编译时解析。编译器是否假设在调试模式下“this”不是nullptr?

但是,如果编译器没有做出这个假设,那么这个断言对于及早发现问题非常有用。

编译器是否会这样做?

+0

'struct foo {int bar; void baz(){bar = 1; }} * crash = 0; crash-> baz();'嘿presto,'this'为NULL。 –

+4

@JonathanPotter是吗? :)我说'crash-> baz()'是未定义的行为,所以之后的任何事情都可能发生。 –

+0

@JonathanPotter:嘿presto,“这个”已经被转化成了一块美味的奶酪。 –

回答

9

不,编译器通常不会这样假设。甚至有商业代码在进行这些检查,有些不仅仅是断言,而是实际上是逻辑。 if (!this) { doSomeWork(); }

虽然你不能达到thisNULL没有运行到未定义的行为的情况下,如果你很清楚实现的细节,那么这是你可以做的检查;是的,你说得对,可以帮助调试

虽然我不会把它放在任何地方。任何地方,就此而言。如果this确实是NULL,那么稍后在访问某个成员时可能会崩溃。如果您未访问任何成员,请考虑标记方法static。它也不必要地膨胀了代码。

+0

你为什么不把它放在任何地方? – qdii

+2

它是过度的 - 无论如何你会崩溃在一个空的解除引用,所以断言失败并没有真正添加任何有用的东西。 –

+0

@qdii我看不到它的收益。 –

3

编译器通常只在开启优化时采取任何操作。所以,如果你编译时没有进行优化(只要你没有定义NDEBUG,那么assert就被启用了,这与优化无关),assert将起作用。

它会遇到常规方法的问题,但请记住,对于虚拟方法,为了调用该方法而取消引用this指针,因此在调用此检查之前已发生崩溃。对于大多数非虚方法来说,如果方法访问任何成员(如果没有,首先不应该成为实例成员函数),问题不会被忽视,因此添加断言是否有意义是个问题。

+0

不,这不总是取消引用来打电话!在非虚拟调用的情况下,则不需要取消引用指针。 –

+0

删除我的意见,与您的编辑它现在没有意义:) – qdii

-2

不,只需要在非虚拟的非静态成员函数中声明它。

在静态成员上,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 
} 
+1

为什么负面的表示法?你应该评论... –

+0

因为“在非虚拟的非静态成员上,由于调用是由编译器静态确定的,所以像ptr-> f()这样的调用可以被翻译成类似f(ptr)的东西,所以你可以有一个null!“这是不正确的。这不是有效的代码,它调用未定义的行为。 (当回答“为什么这个答案错误”时,评论是多余的)在其他答案中。) –

2

要除了那些已经说的是,它使不出来测试thisnullptr。即使指针确实是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; 
} 
+0

如果它只能检测错误*有时*,我仍然会接受它。 – qdii

相关问题