zeus
zeus

Reputation: 29

Null reference check in c++

The following code checks for a null reference and creates an object using new if detected.

The code compiles and the object is created successfully (as anticipated), but the program terminates unexpectedly on the line ref.set_dat(55) in function main() (also shown in comments) which is an unexpected behavior.

I don't seem to understand why does the method call to set_dat() method fail when the object is created successfully using new?

class X {
        private:
            int *_dat,*__dat;
        public:
            X(); // constructor
            ~X(); // destructor
            int get_dat() const {
                return *(this->_dat);
            }
            int get__dat() const {
                return *(this->__dat);
            }
            void set_dat(int data) {
                *(this->_dat)=data;
            }
            void set__dat(int data) {
                *(this->__dat)=data;
            }
    };

    X::X() {
        this->_dat=new int(0); // assign default value of 0
        this->__dat=new int(0);
        cout << "Construction Successful\n";
    }

    X::~X() {
        delete this->_dat;
        delete this->__dat;
        _dat=NULL;
        __dat=NULL;
        cout << "Destruction Successful\n";
    }

    int main() {
        X *obj=NULL;
        X &ref=*obj;
        if (&ref==NULL) {
            cout << "NULL REFERENCE DETECTED\n";
            obj=new X;
        } else { // this must not execute
            cout << "YOU CANT BE HERE!!!\n";
        }
        ref.set_dat(55); // Program terminates at this statement
        cout << "Data 1 has value " << ref.get_dat() << endl;
        delete obj;
        cout << "Delete successful\n";
        obj=NULL;
        if (&ref==NULL) {
            cout << "NULL REFERENCE\nPROGRAM NOW TERMINATES";   
        } else { // this block must not execute
            ref.set_dat(58); 
            ref.set__dat(99);
            cout << "Data 1 now is " << ref.get_dat() << endl;
            cout << "Data 2 now is " << ref.get__dat() << endl;
            delete obj;
        }
        return 0;
    }

Please note that I have tried substituting ref, a reference, with obj->, the original object, but to no avail the same situation is encountered; the program terminates at the same line.

Can anyone please explain me why the program fails to execute at this particular line even after the creation of the object is successful and in the case of an incorrect syntax or logic, suggest me with the correct one? The expected pathway of the program is mentioned in the comments.

Upvotes: 1

Views: 258

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 598329

X *obj=NULL;
X &ref=*obj;

A reference can never be NULL, only a pointer can be NULL. But it is undefined behavior to dereference a NULL pointer. This code is just plain wrong.

Your code re-assigns obj half-way, so the only way that ref can update automatically is if ref refers to the obj variable itself and not to the X object that obj points at:

int main() {
    X *obj = NULL;
    X* &ref = obj; // <-- a reference to a pointer
    if (ref == NULL) { // <-- OK
        cout << "NULL REFERENCE DETECTED\n";
        obj = new X; // <-- ref can now access the X
    } else { // this must not execute
        cout << "YOU CANT BE HERE!!!\n";
    }
    ref->set_dat(55); // <-- OK
    cout << "Data 1 has value " << ref->get_dat() << endl;
    delete obj;
    cout << "Delete successful\n";
    obj = NULL; // <-- ref no longer accesses an X
    if (ref == NULL) { // <-- OK
        cout << "NULL REFERENCE\nPROGRAM NOW TERMINATES";   
    } else { // this block must not execute
        ref->set_dat(58); 
        ref->set__dat(99);
        cout << "Data 1 now is " << ref->get_dat() << endl;
        cout << "Data 2 now is " << ref->get__dat() << endl;
        delete obj;
    }
    return 0;
}

Alternatively, change ref into a pointer instead of a reference:

int main() {
    X *obj = NULL;
    X** ref = &obj; // <-- a pointer to a pointer
    if (*ref == NULL) { // <-- OK
        cout << "NULL REFERENCE DETECTED\n";
        obj = new X; // <-- *ref can now access the X
    } else { // this must not execute
        cout << "YOU CANT BE HERE!!!\n";
    }
    (*ref)->set_dat(55); // <-- OK
    cout << "Data 1 has value " << (*ref)->get_dat() << endl;
    delete obj;
    cout << "Delete successful\n";
    obj = NULL; // <-- *ref no longer accesses an X
    if (*ref == NULL) { // <-- OK
        cout << "NULL REFERENCE\nPROGRAM NOW TERMINATES";   
    } else { // this block must not execute
        (*ref)->set_dat(58); 
        (*ref)->set__dat(99);
        cout << "Data 1 now is " << (*ref)->get_dat() << endl;
        cout << "Data 2 now is " << (*ref)->get__dat() << endl;
        delete obj;
    }
    return 0;
}

Upvotes: 7

Related Questions