2

If a pointer is set to NULL wouldn't any references to it or through it also be NULL. Here is a compilable example that will bomb when you try to run it:

#include <string>
#include <iostream>

#define NULL 0

class Seedcoat {
public:
    //Seedcoat();
    std::string Name;
    int Weight;
};

class Seed {
public:
    //Seed();
    std::string Name;
    int Weight;
    Seedcoat* ItsSeedcoat;
};

class Apple {
public:
    //Apple();
    std::string Name;
    int Weight;
    Seed* ItsSeed;
};

int main()
{
///////Apple Objects Begin///////
    Apple       MyApple;
    Seed        MySeed;
    Seedcoat    MySeedCoat;

    MyApple.ItsSeed = &MySeed;
    MyApple.ItsSeed->ItsSeedcoat = &MySeedCoat;
    MyApple.ItsSeed->ItsSeedcoat->Weight = 2;

    if ( MyApple.ItsSeed != NULL) {
        std::cout << "The weight of the apple seed's seedcoat is " << MyApple.ItsSeed->ItsSeedcoat->Weight <<".\n";
    }

    MyApple.ItsSeed = NULL;

    if ( MyApple.ItsSeed->ItsSeedcoat != NULL) {
        std::cout << "The weight of the apple seed's seedcoat is " << MyApple.ItsSeed->ItsSeedcoat->Weight <<".\n";
    }

    return 0;
}

So my question is: Why does this

MyApple.ItsSeed->ItsSeedcoat != NULL

return true. I would think it would not because ItsSeed is set to NULL - but it still tries to reference the weight value of ItsSeedcoat - and then it bombs I presume because ItsSeed does not exist. I realize there are easy ways to get around this - this example was just to show the behavior I am observing. Is this anything to be concerned about? - or is this normal behavior? What is/are the reason(s) it was done this way? Thanks.

Stepan1010
  • 3,136
  • 1
  • 16
  • 21
  • In addition to the answers given, you should know that you aren't setting the object to NULL. You only set a pointer to NULL. The pointer is not the object. The pointer only points to the object. When you assign a value to that pointer, the object it pointed to previously is not affected at all. – Nikos C. Dec 05 '12 at 22:11
  • That is true. I made an edit to clarify. – Stepan1010 Dec 05 '12 at 22:26
  • `ItsSeed` does exist of course. It's a pointer and it's value is NULL. That means `MyApple.ItsSeed == NULL`. So what you're effectively doing is: `NULL->ItsSeedcoat != NULL`. Obviously that's a NULL pointer dereference. The usual result of a NULL pointer dereference is that the program will crash. – Nikos C. Dec 05 '12 at 22:34
  • Right, the valid address no longer exists - not the pointer itself. I think people (based on the answers) understood what I meant - but feel free to edit the question to make it more clear. Thanks. – Stepan1010 Dec 05 '12 at 22:41

7 Answers7

3

C++ does not hold your hand in such a way. Setting a pointer to null sets only that pointer to null. It doesn't clear any subobjects or free any memory as you might expect in Java or Python.

Once you set the pointer to null, it's no longer legal to access MyApple.ItsSeed->ItsSeedcoat so anything could happen.

In your particular problem I think composition would probably be a better solution. However if you do need to manage memory allocation/deallocation in C++ I highly suggest using an appropriate smart pointer which gives you power approximately equal to that of garbage collectors in other languages.

I do also suggest not defining NULL yourself as some headers already define it for C. In C++03 I typically recommend using the literal 0 while in C++11 you can use the nullptr keyword.

Mark B
  • 95,107
  • 10
  • 109
  • 188
  • As far as my understanding currently goes it is going to require me to write alot more if statements to make sure that everything referenced through a non-existent(null) parent pointer actually exists before I try to do anything with it. – Stepan1010 Dec 05 '12 at 22:21
  • 1
    @Stepan1010 In C++ you usually design your code to not *need* those checks in the first place. You give your classes a set of invariants and then you always know what's safe to access. Sometimes you do need `if` checks (for example in a linked list). – Mark B Dec 05 '12 at 22:42
  • Unfortunately, I didn't design the codebase - I am just using it. I freshened up on the difference between aggregation(which I think is what I am doing) and composition. Since most of the functions of the codebase return pointers - I think I will have to stick with aggregation. But I think I will look into the smart pointers(boost I assume) as well. In any case, it won't be that many if statements(most are non-nested). I was just trying to keep the code clean. I appreciate the insight. I'll investigate them. You get the approval since you offered possible alternatives. Thanks. – Stepan1010 Dec 05 '12 at 23:03
1

After setting MyApple.ItsSeed to NULL, you are not allowed to dereference the pointer MyApple.ItsSeed, meaning that the expression MyApple.ItsSeed->ItsSeedcoat is not allowed.

This won't necessarily throw an exception, but its behavior is undefined.

Ilya Kogan
  • 21,995
  • 15
  • 85
  • 141
1

It's undefined behavior, and anything can happen.

Particulary,

MyApple.ItsSeed = NULL;
if ( MyApple.ItsSeed->ItsSeedcoat != NULL)

You are not allowed to dereference a NULL pointer. It's as simple as that. If you do, any behavior is compliant.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
0

Dereferencing a NULL pointer leads to undefined behavior. In order to get to the member ItsSeedCoat you have to dereference the pointer ItsSeed, which you have already set to NULL.

Mark Ransom
  • 299,747
  • 42
  • 398
  • 622
0

In your example you set MyApple.ItsSeed which is a Seed* to NULL, and then when you do MyApple.ItsSeed->ItsSeedcoat you try to dereference a NULL pointer.

Étienne
  • 4,773
  • 2
  • 33
  • 58
0

After setting a pointer to null, any references to that pointer are also null. In your code, however, you don't have references to the pointer; you have two, totally distinct pointer objects, and what you do to one has no effect on the other. (This is true in every language I know.)

James Kanze
  • 150,581
  • 18
  • 184
  • 329
0

C++ does not implement the kind of behavior that you are describing. In some languages, an object keeps track of all "weak" pointers to it so that when that object is freed, all of those pointers gets NULL'ed automatically. C++ is not one of those language, however. When an object is freed, NO pointers to that object get NULL'ed automatically. When a particular pointer to an object gets NULL'ed, NO other pointers to the same object get NULL'ed automatically. If you need that kind of behavior, look at boost::weak_ptr or std::weak_ptr.

Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770