简体   繁体   English

C ++:为什么不能'this'为nullptr?

[英]c++: why can't 'this' be a nullptr?

In my early days with C++, I seem to recall you could call a member function with a NULL pointer, and check for that in the member function: 在使用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

Doing this may seem silly, but it was absolutely wonderful when writing recursive functions to traverse data structures, where navigating could easily run into the blind alley of a NULL; 这样做似乎很愚蠢,但是在编写用于遍历数据结构的递归函数时绝对很棒,在这种情况下,导航很容易碰到NULL的盲区。 navigation functions could do a single check for NULL at the top and then blithely call themselves to try to navigate deeper without littering the code with additional checks. 导航功能可以在顶部对NULL进行一次检查,然后轻松地调用自身以尝试进行更深入的导航,而不会因附加检查而使代码乱七八糟。

According to g++ at least, the freedom (if it ever existed) has been revoked. 至少根据g ++,自由(如果曾经存在)已被撤销。 The compiler warns about it, and if compiling optimized, it causes crashes. 编译器会对此发出警告,如果对其进行优化编译,则会导致崩溃。

Question 1: does the C++ standard (any flavor) disallow a NULL this? 问题1:C ++标准(任何口味)是否不允许NULL? Or is g++ just getting in my face? 还是g ++刚刚出现在我的面前?

Question 2. More philosophically, why? 问题2.从哲学上讲,为什么? 'this' is just another pointer. “这”只是另一个指针。 The glory of pointers is that they can be nullptr, and that's a useful condition. 指针的荣耀在于它们可以为nullptr,这是一个有用的条件。

I know I can get around this by making static functions, passing as first parameter a pointer to the data structure (hellllo Days of C) and then check the pointer. 我知道我可以通过制作静态函数来解决此问题,将第一个参数传递给数据结构的指针(C的Hellllo Days),然后检查该指针。 I'm just surprised I'd need to. 我只是感到惊讶。

Edit: To upvote an answer I'd like to see chapter and verse from the standard on why this is disallowed. 编辑:要赞成一个答案,我想从标准中查看为什么不允许这样做的章节。 Note that my example at NO POINT dereferences NULL. 请注意,我在NO POINT的示例取消了对NULL的引用。 Nothing is virtual here, and p is copied to "argument this" but then checked before use. 这里没有什么是虚拟的,将p复制到“ argument this”,然后在使用前进行检查。 No defererence occurs! 不会发生延迟! so dereference of NULL can't be used as a claim of UB. 因此对NULL的取消引用不能用作UB的声明。

People are making a knee-jerk reaction to *p and assuming it isn't valid if p is NULL. 人们正在对* p做出下意识的反应,并假设p为NULL时无效。 But it is, and the evidence is here: http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232 In fact it calls out two cases when a pointer, p, is surprisingly valid as *p: when p is null or when p points one element past the end of an array. 但这是事实,证据在这里: http : //www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#232实际上,它指出了两种情况,其中指针p令人惊讶有效为* p:当p为null或p指向数组末尾的一个元素时。 What you must never do is USE the value of *p... other than to take the address of it. 除了获取地址之外,永远不要使用* p ...的值。 &*p where p == nullptr for any pointer type p IS valid. &* p其中p == nullptr对于任何指针类型p是有效的。 It's fine to point out that p->x() is really (*p).x(), but at the end of the day that translates to x(&*p) and that is perfectly well formed and valid. 可以很好地指出p-> x()确实是(* p).x(),但归根结底,它转换为x(&* p)且格式正确且有效。 For p=nullptr... it simply becomes x(nullptr). 对于p = nullptr ...,它只是变成x(nullptr)。

I think my debate should be with the standards community; 我认为我的辩论应该在标准界进行。 in their haste to undercut the concept of a null reference, they left wording unclear. 他们急于削弱空引用的概念,但措辞不清楚。 Since no one here has demanded p->x() is UB without trying to demand that it's UB because *p is UB; 因为这里没有人要求p-> x()是UB而没有试图要求它是UB,因为* p是UB; and because *p is definitely not UB because no aspect of x() uses the referenced value, I'm going to put this down to g++ overreaching on a standard ambiguity. 并且因为* p绝对不是UB,因为x()的任何方面都没有使用引用的值,所以我将其归结为g ++在标准歧义上的过度使用。 The absolutely identical mechanism using a static function and extra parameter is well defined, so it's not like it stops my refactor effort. 使用静态函数和额外参数的绝对相同的机制已得到很好的定义,因此这并不会阻止我的重构工作。 Consider the question withdrawn; 考虑撤回的问题; portable code can't assume this==nullptr will work but there's a portable solution available, so in the end it doesn't matter. 可移植的代码不能假设this == nullptr可以工作,但是有一个可移植的解决方案可用,所以最后没关系。

To be in a situation where this is nullptr implies you called a non-static member function without using a valid instance such as with a pointer set to nullptr . 要在所处的环境thisnullptr意味着你称为非静态成员函数,而无需使用一个有效的实例,如用指针设置为nullptr Since this is forbidden, to obtain a null this you must already be in undefined behavior. 由于这是禁止的,获得一个空this ,你必须已经在不确定的行为。 In other words, this is never nullptr unless you have undefined behavior. 换句话说, this是从来没有nullptr除非你具有不确定的行为。 Due to the nature of undefined behavior, you can simplify the statement to simply be " this is never nullptr " since no rule needs to be upheld in the presence of undefined behavior. 由于未定义行为的性质,您可以将语句简化为“ this绝不是nullptr ”,因为在存在未定义行为的情况下无需遵循任何规则。

Question 1: does the C++ standard (any flavor) disallow a NULL this? 问题1:C ++标准(任何口味)是否不允许NULL? Or is g++ just getting in my face? 还是g ++刚刚出现在我的面前?

The C++ standard disallows it -- calling a method on a NULL pointer is officially 'undefined behavior' and you must avoid doing it or you will get bit. C ++标准不允许这样做- 在NULL指针上调用方法是正式的“未定义行为”,您必须避免这样做,否则会有点麻烦。 In particular, optimizers will assume that the this-pointer is non-NULL when making optimizations, leading to strange/unexpected behaviors at runtime (I know this from experience :)) 特别是,优化器在进行优化时将假定this-pointer为非NULL,从而在运行时导致奇怪/意外的行为(我从经验中知道这一点:)

Question 2. More philosophically, why? 问题2.从哲学上讲,为什么? 'this' is just another pointer. “这”只是另一个指针。 The glory of pointers is that they can be nullptr, and that's a useful condition. 指针的荣耀在于它们可以为nullptr,这是一个有用的条件。

I'm not sure it matters, really; 我不确定这是否真的重要; it's what is specified in the C++ standard, and they probably had their reasons (philosophical or otherwise), but since the standard specifies it, the compilers expect it, therefore as programmers we have to abide by it, or face undefined behavior. 这是C ++标准中指定的内容,并且可能有其原因(从哲学上或其他方面),但是由于该标准指定了它,因此编译器期望这样做,因此,作为程序员,我们必须遵守它,否则将面临不确定的行为。 (One can imagine an alternate universe where NULL this-pointers are allowed, but we don't live there) (可以想象一个替代的宇宙,其中允许使用此指针为NULL,但我们不住在那儿)

C++ does not allow calling member functions of null object. C ++不允许调用null对象的成员函数。 Objects need identity and that can not be stored to null pointer. 对象需要身份并且不能存储为空指针。 What would happen if member function would read or write a field of a object referenced by null pointer? 如果成员函数将读取或写入由空指针引用的对象的字段,将会发生什么?

It sounds like you could use null object pattern in your code to create wanted result. 听起来您可以在代码中使用空对象模式来创建所需的结果。

Null pointer is recognised a problematic entity in object oriented languages because in most languages it is not a object. 空指针在面向对象的语言中被认为是有问题的实体,因为在大多数语言中它不是对象。 This creates a need for code that specifically handles the case something being null. 这产生了对专门处理空值的代码的需求。 While checking for special null pointer is the norm. 在检查特殊的空指针时,这是常态。 There are other approaches. 还有其他方法。 Smalltalk actually has a NullObject which has methods its own methods. Smalltalk实际上有一个NullObject,它具有自己的方法。 As all objects it can also be extended. 作为所有对象,也可以扩展。 Go programming language does allow calling struct member functions for something that is nil (which sounds like something required in the question). Go编程语言确实允许为零的某些东西调用struct成员函数(这听起来像是问题中所需要的东西)。

The question has already been answered - it is undefined behavior to dereference a null pointer, and using *obj or obj-> are both dereferencing. 该问题已经得到解答-取消引用空指针是未定义的行为,并且使用*objobj->都在取消引用。

Now (since I assume you have a question on how to work around this) the solution is to use static function: 现在(因为我假设您对如何解决此问题有疑问),解决方案是使用静态函数:

class Foo {
    static auto bar_st(Foo* foo) { if (foo) return foo->bar(); }
}

Having said that, I do think that gcc's decision of eliminating all branches for nullptr this was not a wise one. 话虽如此,我确实认为gcc决定删除nullptr的所有分支的决定并不明智。 Nobody gained by that, and a lot of people suffered. 没有人从中受益,许多人遭受了痛苦。 What's the benefit? 有什么好处?

this太多,如果你可能为空delete this (这是可能的,但不推荐)

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

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