编译器是否假设“this”在调试模式下不是 nullptr?

问题描述 投票:0回答:4

我想知道将

assert( this != nullptr );
放在每个成员函数上是否是一个好主意。我相信编译器可以决定完全忽略这个断言,因为假设
this
不能为空,因此断言始终为真并且可以在编译时解析。

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

编译器会假设这一点吗?

c++ this assert
4个回答
9
投票

不,编译器通常不会这么假设。甚至还有商业代码与这些检查相关,有些不仅仅是断言,而且实际上是其中的逻辑。

if (!this) { doSomeWork(); }

尽管您无法达到

this
NULL
的情况而不遇到未定义的行为,但如果您非常了解实现细节,那么您可以进行检查;是的,你是对的,它可以帮助调试。

不过我不会把它到处放。任何地方,就此而言。如果

this
确实是
NULL
,稍后当您访问某个成员时可能会发生崩溃。如果您不访问任何成员,请考虑标记该方法
static
。它还会不必要地使代码变得臃肿。


3
投票

编译器通常仅在打开优化时做出任何假设。因此,如果您在没有优化的情况下进行编译(只要您不定义

assert
,即启用
NDEBUG
,这与优化无关),则断言将起作用。

它将捕获普通方法的问题,但请记住,对于虚拟方法,

this
指针被取消引用,以便调用该方法,因此在调用此检查之前已经发生了崩溃。对于大多数非虚拟方法,如果该方法访问任何成员,问题就不会被忽视(如果没有,那么它首先就不应该是实例成员函数),因此添加断言是否有意义是个问题.


2
投票

除了已经说过的内容之外,测试

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;
}

-2
投票

不,只需要在非虚拟非静态成员函数上断言它。

在静态成员上,

this
是被禁止的,所以没关系。

在非虚拟非静态成员上,由于调用是由编译器静态确定的,因此像

ptr->f()
这样的调用可以转换为类似
f(ptr)
的东西,所以你可以有一个 null
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
}
© www.soinside.com 2019 - 2024. All rights reserved.