Kaio1012
Kaio1012

Reputation: 25

How to prevent calling a non-static function of an uninitialized C++ object

Below is a minimal example of problem that occurred in a huge legacy project I am currently working on.

I have a main function that should be creating a new object ob a global object pointer B* B. Because of a configuration error this was not done and the non-static method b->do_something() was called. My expectation would be that this leads to a segmentation fault when doing so.

The code does create a segmentation fault but only when comparing a == nullptr. This was extremely confusing to me because I was looking for problems with the initialization of a. I was not aware that calling a non-static method of an object is possible even when this object was never initialized.

My question is how to prevent this confusion in the future? So how do I crash the execution when calling a non-static method of a NULL object?

Possible solutions that do not satisfy me yet:

#include <stdio.h>
#include <stdexcept>

class A {};

class B {
    A *a = nullptr;
public:
    B(){
        // Sometimes doing this
        a = new A();
    }
    void do_something() {
        if(a == nullptr){ // SegFault appears here because B was never created and accessing this->a evaluates to nullptr->a
            throw std::runtime_error("Error");
        } else {
            printf("Doing Something");
        }
    } 
};


// Global variable
B *b;

int main()
{
    // Long code that should have called:
    // b = new B();
    b->do_something();

    return 0;
}

Upvotes: 0

Views: 166

Answers (1)

463035818_is_not_an_ai
463035818_is_not_an_ai

Reputation: 122830

You cannot prevent a user from all possible mistakes and most of the time it is futile to even try (this isnt Java ;). Thou shall not call a member on a non-initialized pointer (actually in your code it is initialized because it is global, but with nullptr). Thats not specific to your class, but something one has to consider always when using pointers.

However, there are ways to mitigate the problem. You could make B::do_something private and be-friend a free function:

void do_something(B* b) {
    if (b) b->do_something();
}

Its not very clear from your minimal example, but if do_something can be implemented as non-member, then you do not need the member function in the first place.

My question is how to prevent this confusion in the future? So how do I crash the execution when calling a non-static method of a NULL object?

There is no portable way to do that. Calling a member function on a nullptr is undefined behavior. Anything can happen, including it appears to work. If you remove the check for a being nullptr then do_something is actually not using this and most probably will appear to work with most compilers.

Checking this != nullptr inside the method is also no help, because once the call is made, you are already in undefined behavior.

Upvotes: 2

Related Questions