c++:成员函数中的"this == nullptr"安全吗?

c++: Is `this == nullptr` safe in member functions?

本文关键字:quot nullptr 安全 this 函数 c++ 成员      更新时间:2023-10-16

要计算二叉树的高度,使用height(left)+height(right)+1并将不存在的节点的高度定义为-1。因此,如果 left 或 right 为 null,则公式无需显式指定这些情况即可工作。

我在 C++ 年实现了这个想法,并确保成员函数在this == nullptr时不会访问成员变量。我的实现是成功的并且有效(至少在我的 Linux 机器上(。

我想找出这种方法可能具有什么样的实际缺点,以及标准是否对此有所规定。所以,这是我的问题。

#include <algorithm>
#include <iostream>
struct Node {
// default values of the child nodes are NULL
Node *left = nullptr;
Node *right = nullptr;
// store some value
int v;
int get_height() const __attribute__ ((optimize(0))) {
if (this == nullptr)
return -1;
return std::max(left->get_height(), right->get_height()) + 1;
}
};
int main() {
Node node1, node2, node3, node4;
node2.left = &node1;
node2.right = &node3;
node3.right = &node4;
std::cout << node2.get_height() << std::endl;
return 0;
}

编辑:如果启用了优化,则代码将失败并出现分段错误。可以通过将__attribute__ ((optimize(0)))附加到函数来解决问题。

this == nullptr是"安全的",因为它没有任何副作用。

this == nullptr无用的,因为在任何具有明确定义行为的程序中,它永远不会true。因此,允许优化器假装您编写了:

if (false)
return -1;
return std::max(left->get_height(), right->get_height()) + 1;

这与编写相同:

return std::max(left->get_height(), right->get_height()) + 1;

不安全的做法是通过 null 指针(或任何其他不指向具有活动生存期的对象的指针(调用成员函数。这种检查并不能防止这种情况,即使人们可能直觉地认为它确实如此。示例程序的行为未定义。

函数定义良好的实现示例:

int get_height() const {
int lh = left  ? left->get_height()  : -1;
int rh = right ? right->get_height() : -1;
return std::max(lh, rh) + 1;
}

非成员函数可能有助于避免一点点重复。

<小时 />

附言一个好的编译器会警告你潜在的错误:

警告:"this"指针在定义良好的C++代码中不能为 null;可以假定比较总是计算为 false [-Wtautological-undefined-compare]

if (this == nullptr)
^~~~    ~~~~~~~

不,if (this == nullptr)不是"安全的"。 if 语句可能为真的唯一方法是,如果您在空指针上调用了成员函数,并且这样做是未定义的行为。 这意味着支票是完全多余的,因为它在法律代码中永远不可能是真的。

this不能nullptr,编译器可能会优化它,因为this为空指针是UB的结果。

类似案例:

ptr->someStaticMethod();   // if ptr is null this is an UB, even if method is static.
if(!ptr) 
abort();   // May never happen, even if ptr is nullptr

如果您希望能够在尝试获取对象高度的同时处理nullptr,则应使用非成员函数。

namespace MyApp
{
int get_height(Node const* n)
{
return ( n == nullptr ) ? -1 : n->get_height();
}
}

和使用

Node* n = ...;
...
int h = MyApp::get_height(n);