繁体   English   中英

将NULL指针转换为对象并调用其成员函数之一是否有实际好处?

[英]Is there a practical benefit to casting a NULL pointer to an object and calling one of its member functions?

好的,所以我知道技术上这是未定义的行为,但是,我在生产代码中不止一次地看到过这种情况。 如果我错了,请纠正我,但我也听说有些人使用这个“功能”作为当前C ++标准缺乏方面的合理替代,即无法获得地址(嗯,成员函数的真正偏移)。 例如,这不是PCRE(Perl兼容的正则表达式)库的流行实现:

#ifndef offsetof
#define offsetof(p_type,field) ((size_t)&(((p_type *)0)->field))
#endif

人们可以争论在这样的情况下利用这种语言的微妙性是否有效,甚至是否有必要,但我也看到它的用法如下:

struct Result
{
   void stat()
   {
      if(this)
         // do something...
      else
         // do something else...
   }
};

// ...somewhere else in the code...

((Result*)0)->stat();

这很好用! 它通过测试的存在,避免了空指针引用this ,它不尝试访问类成员的else块。 只要这些警卫到位,这是合法的代码,对吗? 所以问题仍然存在:是否有一个实际的用例,人们可以从使用这样的结构中受益? 我特别关注第二种情况,因为第一种情况更多是语言限制的解决方法。 或者是吗?

PS。 对C风格的演员表示抱歉,不幸的是,如果可以的话,人们仍然喜欢打字。

第一种情况是没有召唤任何东西。 这是在拿地址 这是一个定义的,允许的操作。 它产生从对象开始到指定字段的偏移量(以字节为单位)。 这是一种非常非常常见的做法,因为非常普遍需要这样的偏移。 毕竟,并非所有对象都可以在堆栈上创建。

第二种情况是相当愚蠢的。 明智的做法是将该方法声明为静态。

我没有看到((Result*)0)->stat(); - 这是一个丑陋的黑客,可能会比以后更快地破坏。 适当的C ++方法将使用静态方法Result::stat()

另一方面,offsetof()是合法的,因为offsetof()宏实际上从不实际调用方法或访问成员,而只执行地址计算。

其他人都很好地重申了这种行为是不确定的。 但是假设它不是,并且在某些情况下允许p->member以一致的方式运行,即使p不是有效指针。

你的第二个结构仍然几乎没有用处。 从设计的角度来看,如果一个函数可以在访问成员和不访问成员的情况下完成它的工作,那么你可能做错了。如果它可以将代码的静态部分拆分成一个单独的静态函数会更合理比期望用户创建一个空指针来操作。

从安全的角度来看,你只对保护的无效的方式一小部分this指针可以被创建。 对于初学者来说,有未初始化的指针:

Result* p;
p->stat(); //Oops, 'this' is some random value

有些指针已经初始化,但仍然无效:

Result* p = new Result;
delete p;
p->stat(); //'this' points to "safe" memory, but the data doesn't belong to you

即使你总是初始化你的指针,绝对不会意外地重用free'd内存:

struct Struct {
    int i;
    Result r;
}
int main() {
    ((Struct*)0)->r.stat(); //'this' is likely sizeof(int), not 0
}

所以,即使它不是未定义的行为,它也是毫无价值的行为。

虽然针对特定C ++实现的库可能会这样做,但这并不意味着它通常是“合法的”。

这很好用! 它通过测试它的存在来避免空指针取消引用,并且它不会尝试访问else块中的类成员。 只要这些警卫到位,这是合法的代码,对吗?

不,因为虽然它可能在一些C ++实现上工作正常,但它完全可以不适用于任何符合要求的C ++实现。

取消引用空指针是未定义的行为,如果你这样做会发生任何事情。 如果你想要一个有效的程序,不要这样做。

仅仅因为它不会立即崩溃在一个特定的测试用例中并不意味着它不会让你遇到各种各样的麻烦。

未定义的行为是未定义的行为。 这样做会为你的特定编译器“工作”吗? 好吧,可能。 他们会为下一次迭代工作吗? 或另一个编译器? 可能不是。 你支付你的钱,你可以选择。 我只能说,在将近25年的C ++编程中,我从未觉得有必要做任何这些事情。

关于声明:

它通过测试它的存在来避免空指针取消引用,并且它不会尝试访问else块中的类成员。 只要这些警卫到位,这是合法的代码,对吗?

代码不合法​​。 当指针为NULL时,无法保证编译器和/或运行时实际调用该方法。 该方法中的检查是没有帮助的,因为你不能假设的方法实际上将最终被称为一个NULL this指针。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM