1

I've got a couple of questions regarding pointers. First:

 ObjectType *p; 
 p->writeSomething();

Why is it possible to call a method on an object when the pointer hasn't been initialized? If I run that code I get the output from "writeSomething()" in my console window. Second:

ObjectType *p;
if(p==NULL) 
cout<<"Null pointer";//This is printed out
p = new ObjectType;
delete p;
if(p==NULL)
   cout<<"Null pointer";
else
   cout<<"Pointer is not null";//This is printed out

Why isn't the pointer null in the second if statement and how do I check if a pointer isn't pointing to any memory address? I'm also wondering if there is any way to check if some memory hasn't been released when a program is done executing. For example, if you forget to write 1 delete statement in the code.

user1163392
  • 167
  • 1
  • 1
  • 8
  • Any chance that `writeSomething()` is a static method? – Hristo Iliev May 19 '12 at 10:01
  • 1
    These are some of the good reasons not to use regular, dumb pointers. There are any number of smart pointers available that don't have these annoying quirks. – David Schwartz May 19 '12 at 10:07
  • @HristoIliev I doesn't have to be a static method. If it doesn't access any members, then it has a very good chance of working. And even if it did access members, it could still work sometimes. It's undefined behavior, anything could happen. – Paul Manta May 19 '12 at 10:07
  • @PaulManta, so if I understand correcly, if there are no virtual methods in the class inheritance up to `ObjectType`, then `writeSomething()` is _usually_ resolved at compile time and `p` is just passed as the `this` argument? Then if `writeSomething()` doesn't access any non-static member variable then _most likely_ it will work even with `this == NULL`. – Hristo Iliev May 19 '12 at 10:21
  • 1
    @HristoIliev If what you're calling is not a virtual method, it is always resolved a compile time. And yes, the pointer will be passed as `this` and in some cases, it might work. But don't count on it. – Paul Manta May 19 '12 at 10:31
  • "...check if a pointer isn't pointing to any memory address?" a pointer always points to some memory address, the question is whether it's a valid address and even in case it's valid whether it's initialized with the correct type or not. The former can be checked using the OS, the later is just impossible with any sane implementation. – Yakov Galka May 19 '12 at 10:45
  • possible duplicate of [When does invoking a member function on a null instance result in undefined behavior?](http://stackoverflow.com/questions/2474018/when-does-invoking-a-member-function-on-a-null-instance-result-in-undefined-beha) – Bo Persson May 19 '12 at 11:08

4 Answers4

7

The first code is undefined behavior, anything can happen, even appearing to work. It's probably working because the call is resolved statically, and you're not accessing any members of the class.

For the second snippet delete doesn't set the pointer to NULL, it just releases the memory. The pointer is now dangling, as it points to memory you no longer own.

Luchian Grigore
  • 253,575
  • 64
  • 457
  • 625
  • So, to be safe, every time I delete a pointer I should set it equal to null? – user1163392 May 19 '12 at 10:04
  • No, don't do that. That leads to very bad habits. Just don't use the pointer. (Or use smart pointers instead of dumb pointers.) – David Schwartz May 19 '12 at 10:05
  • 2
    @user1163392 depends. Sometimes, you don't have to, but most of the time, if you must use pointers, yes, set them to NULL. But try using smart pointers where possible. – Luchian Grigore May 19 '12 at 10:07
  • @DavidSchwartz If he's going to use raw pointers, setting them to `nullptr` when they don't point to anything hardly seems like a bad habit. – Paul Manta May 19 '12 at 10:09
  • @LuchianGrigore: That's very bad advice, IMO. For one thing, there's no way you can change other pointers that point to the same object. So you can't rely on it. – David Schwartz May 19 '12 at 10:09
  • @PaulManta: What if two pointers point to the same object? How do you set the other one? You can't rely on code that deletes an object being able to find every pointer that refers to that object. [See here](http://stackoverflow.com/a/1879469/721269). – David Schwartz May 19 '12 at 10:10
  • 1
    @DavidSchwartz That's a flaw in design then, if some part of the code deletes memory that is being used by another. It has nothing to do with setting pointers to null. – Paul Manta May 19 '12 at 10:11
  • @DavidSchwartz of course you can't rely on it, but it's better than nothing. :) I don't think it's bad advice. – Luchian Grigore May 19 '12 at 10:11
  • @PaulManta: Right. So you *still* have to keep track. So what's the point of setting the pointer to null? It doesn't save you anything. (And Luchian: The problem is that people rely on it and think it means they don't have to keep track, leading to more bugs than it avoids.) – David Schwartz May 19 '12 at 10:12
  • @DavidSchwartz What if the rest of the code depends on it. You `delete` the pointer if some condition is met, or in some specific case, and later you only need to operate on that pointer if it's not null... – Luchian Grigore May 19 '12 at 10:14
  • @DavidSchwartz At any rate, setting them to null means fewer chances to mess up. But you shouldn't have situations where you delete memory that is in use in the first place. – Paul Manta May 19 '12 at 10:14
  • @LuchianGrigore: In that case, setting the pointer to NULL *is* the way you keep track. You have to keep track somehow. The problem is, in many cases setting the pointer to NULL isn't sufficient. So telling people to do it makes no sense. Tell them to keep track. If setting the pointer to NULL keeps track, then good, that's what you've told them to do. If not, then there's no point and the harm is that they'll think it's sufficient. – David Schwartz May 19 '12 at 10:15
  • @DavidSchwartz Ok I see your point. I guess I am used to keeping track by setting pointers to NULL in my code. :) – Luchian Grigore May 19 '12 at 10:16
  • @PaulManta: Setting them to NULL means more chances to mess up. Because you'll expect that a pointer that points to memory that has been freed will be NULL. And if you call `delete` where it's incorrect for the program logic, you *want* it to break horribly if possible. Not succeed silently. (No, my argument is: don't tell novices to implement solutions that only work some of the time because they'll use them even where they're insufficient or useless.) – David Schwartz May 19 '12 at 10:17
  • @DavidSchwartz When you delete a pointer and then still try to access the memory, it might work, it might not work. However, if you delete it and then make it null, it will always fail immediately. Non-null pointers can be deferenced (even if they point to nothing); null pointers cannot. – Paul Manta May 19 '12 at 10:19
  • @PaulManta well, technically, you can dereference null pointers. And it might appear to work (as the op pointed out in the first snippet). – Luchian Grigore May 19 '12 at 10:20
  • 1
    @PaulManta: Since you can just as easily access it through another pointer, it doesn't matter. And since this will make an errant `delete` silently succeed, it hides just as many errors as it exposes. – David Schwartz May 19 '12 at 10:20
  • @DavidSchwartz I'd rather have some parts of my code be safe than have all of them be unsafe. I honestly can't see how *not* setting a pointer to null can expose problems or make the programmer more aware. All I can see coming out of this practice is lots of silent errors. – Paul Manta May 19 '12 at 10:28
  • 1
    @PaulManta: If there's a delete later in the code that shouldn't be there, setting the pointer to NULL will make the delete succeed silently some of the time. (It may even encourage you to put it there "just in case" to avoid a leak. It's harmless right? If the object was already deleted, the pointer is NULL, right?) Then in the failure case (where the object is deleted elsewhere, of course that can't set this pointer to NULL) the code will fail horribly. – David Schwartz May 19 '12 at 10:30
  • @DavidSchwartz But you're talking about badly design programs. Badly designed programs are hopeless. If someone deletes memory that I'm using there's nothing I can do. Setting the pointer to null won't prevent others from accessing that same memory, but it will prevent me. But, again, there shouldn't be cases where you delete memory that is in use in the first place. – Paul Manta May 19 '12 at 10:35
  • @PaulManta: I'm not talking about someone deleting memory that you're using. I'm talking about someone deleting memory because it's no longer in use and then other code deleting it "just in case" it didn't get deleted. Because, after all, if it was deleted the pointer would be NULL. See [this link](http://stackoverflow.com/questions/1025589/setting-variable-to-null-after-free/1879469#1879469) and comments. – David Schwartz May 19 '12 at 10:38
  • @DavidSchwartz Why would my copy of the pointer be null if it was deleted some other place? – Paul Manta May 19 '12 at 10:41
  • @PaulManta: It wouldn't. That's why you can't sprinkle your code with `delete`s "just to be safe". Whether or not you NULL pointers after `delete`s, you still have to make sure, every time you dereference a pointer or delete it, that the pointer's contents are still valid. – David Schwartz May 19 '12 at 10:42
  • 1
    let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/11456/discussion-between-paul-manta-and-david-schwartz) – Paul Manta May 19 '12 at 10:43
3

Your code does of course exhibit undefined behaviour, but here's an example of why it may appear possible to call a member function even if there is no object: If the member function doesn't refer to any member objects of the class, then it will never need to access any part of the memory which you haven't initialized. That means, your member function is essentially static.

As you know, member functions can be considered as normal, free functions which have an implicit instance object reference argument. For example, a simple class Foo defined like this,

struct Foo
{
    void bar() { std::cout << "Hello\n"; }
};

could be implemented as a single, free function:

void __Foo_bar(Foo * this)
{
    std::cout << "Hello\n";
}

Now when you say Foo * p; p->bar();, this amounts to a free function call __Foo_bar(p);. You end up passing an invalid pointer to the function, but since the function never makes use of the pointer, no harm is done.

On the other hand, if your class had a member object, like int Foo::n;, and if the member function was trying to access it, your implementation would try and access this->n, which would very likely cause an immediate problem since you'd actually be dereferencing an invalid pointer.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
2
delete p;

deallocates memory, but it does not change the value of the address stored in p.

There is no method in standard C++ to detect that a pointer is referring to invalid memory. It is your responsibility not to de-reference an invalid pointer.

Your first example is undefined behaviour. One of the possible outcomes of undefined behaviour is that the program works the way you intended it to. Again, it is your responsibility not to write programs with undefined behaviour.

In your code, writeSomething() is probably a non-virtual member function that does not de-reference this which is why it happens to work for you, on your compiler. Most likely if you tried to refer to some member data fields then you would encounter a runtime error.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
0

delete would call upon the destructor of ObjectType followed by de-allocation of memory but it doesn't explicitly makes your pointer NULL

That is something you have to do as a good programming practice.

Jay D
  • 3,263
  • 4
  • 32
  • 48