在我使用C ++的早期,我似乎记得你可以使用NULL指针调用成员函数,并在成员函数中检查它:
class Thing {public: void x();}
void Thing::x()
{ if (this == NULL) return; //nothing to do
...do stuff...
}
Thing* p = NULL; //nullptr these days, of course
p->x(); //no crash
这样做可能看起来很愚蠢,但在编写递归函数来遍历数据结构时,这绝对是非常好的,导航数据结构很容易进入NULL的盲道;导航函数可以在顶部单独检查NULL,然后轻松地调用自己尝试更深入地导航,而不会乱丢代码并进行额外的检查。
至少根据g ++,自由(如果它曾经存在)已被撤销。编译器警告它,如果编译优化,它会导致崩溃。
问题1:C ++标准(任何风格)是否禁止使用NULL?或者g ++只是在我面前?
问题2.更哲学,为什么? '这'只是另一个指针。指针的荣耀在于它们可以是nullptr,这是一个有用的条件。
我知道我可以通过创建静态函数来解决这个问题,将第一个参数传递给数据结构(hellllo Days of C),然后检查指针。我很惊讶我需要。
编辑:为了提出答案,我希望看到关于为什么不允许这样做的标准的章节和经文。请注意,我在NO POINT处的示例取消引用NULL。这里没有什么是虚拟的,并且p被复制到“参数this”但在使用之前被检查。没有任何差别!因此,取消引用NULL不能用作UB的声明。
人们对* p做出了下意识的反应,并假设如果p为NULL则无效。但确实如此,证据在这里:http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232事实上,当一个指针p出乎意料地有效时,它会调出两种情况:* p:当p为null或p指向一个元素超过数组末尾时。你必须做的就是使用* p的值......除了获取它的地址。 &* p其中p == nullptr表示任何指针类型p都有效。可以指出p-> x()实际上是(* p).x(),但在一天结束时转换为x(&* p)并且形成得非常好且有效。对于p = nullptr ...它只是变成x(nullptr)。
我认为我的辩论应该与标准界有关;他们急于削弱空引用的概念,他们的措辞不清楚。因为这里没有人要求p-> x()是UB而不试图要求它是UB,因为* p是UB;并且因为* p绝对不是UB,因为x()的任何方面都没有使用引用的值,我将把它归结为g ++对标准歧义的超越。使用静态函数和额外参数的绝对相同的机制已经很好地定义了,所以它不会停止我的重构工作。考虑撤回的问题;可移植代码不能假设这个== nullptr会工作但是有一个可移植的解决方案,所以最后它没关系。
在this
是nullptr
的情况下,意味着你调用非静态成员函数而不使用有效的实例,例如将指针设置为nullptr
。由于这是禁止的,要获得null this
,您必须已经处于未定义的行为。换句话说,除非你有未定义的行为,否则this
永远不会是nullptr
。由于未定义行为的性质,您可以将语句简化为“this
is never nullptr
”,因为在存在未定义的行为时不需要维护规则。
问题1:C ++标准(任何风格)是否禁止使用NULL?或者g ++只是在我面前?
C ++标准不允许它 - calling a method on a NULL pointer是正式的“未定义行为”,你必须避免这样做,否则你会得到一点点。特别是,优化器会假设在进行优化时this-pointer是非NULL的,在运行时会导致奇怪/意外的行为(我从经验中知道:)
问题2.更哲学,为什么? '这'只是另一个指针。指针的荣耀在于它们可以是nullptr,这是一个有用的条件。
我不确定这很重要,真的;这是C ++标准中规定的内容,它们可能有其原因(哲学或其他方面),但由于标准规定了它,编译器会指望它,因此作为程序员我们必须遵守它,或者面对未定义的行为。 (可以想象一个替代的宇宙,其中允许NULL指针,但我们不住在那里)
问题已经得到解答 - 取消引用空指针是未定义的行为,使用*obj
或obj->
都是解除引用。
现在(因为我假设你有一个关于如何解决这个问题的问题)解决方案是使用静态函数:
class Foo {
static auto bar_st(Foo* foo) { if (foo) return foo->bar(); }
}
话虽如此,我确实认为gcc决定取消nullptr的所有分支并不是一个明智的决定。没有人从中获益,很多人都遭受了苦难。有什么好处?
C ++不允许调用null对象的成员函数。对象需要标识,并且无法存储为空指针。如果成员函数读取或写入由空指针引用的对象的字段,会发生什么?
听起来你可以在你的代码中使用null object pattern来创建想要的结果。
空指针在面向对象语言中被识别为有问题的实体,因为在大多数语言中它不是对象。这就需要专门处理大小写为null的代码。检查特殊空指针是常态。还有其他方法。 Smalltalk实际上有一个NullObject,它有自己的方法。作为所有对象,它也可以扩展。 Go编程语言允许调用struct成员函数为nil(听起来像问题中需要的东西)。
如果你this
(可能但不推荐),delete this
也可能为null