Search code examples
c++thisnullptr

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


To calculate the height of a binary tree, height(left)+height(right)+1 is used and the height of non-existent nodes are defined as -1. So, if left or right is null, then the formula works without specifying these cases explicitly.

I implemented this idea in C++, and I ensured that the member functions will NOT access member variables if this == nullptr. My implementation is successful and works (at least on my Linux machine).

I want to find out what kind of practical downsides this approach can have, and if the standard stipulates anything about it. So, that's my question.

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

Edit: If optimization are enabled the code fails with a segmentation fault. It is possible to fix the problem by appending __attribute__ ((optimize(0))) to the function.


Solution

  • this == nullptr is "safe" in the sense that it has no side-effects whatsoever.

    this == nullptr is useless in the sense that in any program with well defined behaviour, it is never true. As such, the optimizer is allowed to pretend that you had instead written:

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

    Which is same as having written:

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

    What isn't safe is calling a member function through a null pointer (or any other pointer that doesn't point to an object with active lifetime). This check doesn't protect against that, even though one might intuitively think that it does. The behaviour of the example program is undefined.

    An example of well defined implementation of the function:

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

    A non-member function may be useful in avoiding the little bit of repetition.


    P.S. A good compiler will warn you about the potential mistake:

    warning: 'this' pointer cannot be null in well-defined C++ code; comparison may be assumed to always evaluate to false [-Wtautological-undefined-compare]

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