1

I can't understand how deleting of objects and setting pointer to null works.

For example:

Class* c = new Class();

we can set pointer to null

c=null;

in this case object still in the memory and nothing points at it. How we gonna delete it?

or

delete c;

in this case we delete an object, but pointer still points to address location of previous object. In which cases that may be useful?

Yura
  • 85
  • 6
  • This is why you must `delete c` and then set c to null... – Yves Apr 23 '18 at 00:49
  • So, deleting and then setting to null should always come together? – Yura Apr 23 '18 at 00:52
  • 3
    If you don't `delete` the object, and no longer have any pointers or references to it, then you *can't* delete it. It's a so-called *leak*. Don't do that. And `delete` destructs the object and free's the memory associated with it, that's all it is specified to do. – Some programmer dude Apr 23 '18 at 00:52
  • 1
    If we just set to null, that is the worst programming practice? Since object gonna linger somewhere in the memory with almost no way of being accessed? – Yura Apr 23 '18 at 00:53
  • 2
    And if you should pair the destruction of the object and the setting of pointers to it depends a *lot* on your code, your use-cases and your design. In most cases it's not needed and the assignment is a useless operation. – Some programmer dude Apr 23 '18 at 00:54
  • 1
    What you *should* do, always, is to pair every `new` with a `delete`, and every `new[]` with a `delete[]`. However, these days the need for plain simple pointers are becoming less and less needed, except for polymorphism (virtual functions, abstract interface classes and such). For resource-like object use [`std::unique_ptr`](http://en.cppreference.com/w/cpp/memory/unique_ptr) or [`std::shared_ptr`](http://en.cppreference.com/w/cpp/memory/shared_ptr). For dynamic arrays use [`std::vector`](http://en.cppreference.com/w/cpp/container/vector). – Some programmer dude Apr 23 '18 at 00:59
  • Lastly, consider [the rule of zero](http://en.cppreference.com/w/cpp/language/rule_of_three#Rule_of_zero) for your classes to avoid most manual handling of such things. – Some programmer dude Apr 23 '18 at 01:00
  • One more question, little bit offtopic. I declare a pointer Class* a; and then somewhere in code assign to it an object. How to see whether something is assigned to it or not? if(a==NULL) didn't work – Yura Apr 23 '18 at 01:01
  • Unless you initialize the pointer to be a null-pointer, then there's no way do see if it's valid or not. Uninitialized local non-static variables, or uninitialized member variables, are not initialized, and their values will be *indeterminate*. Using them in anyway other than to initialize them leads to *undefined behavior*. It doesn't matter if it's a pointer or not. – Some programmer dude Apr 23 '18 at 01:06
  • It’s important to understand how heap allocation and deallocation works, so good for asking. In practice, you will usually want to use a wrapper like `std::unique_ptr` to manage your memory with RIIA, or `std::shared_ptr` to manage your memory by counting references. Both will automatically delete the object for you when you no longer need it (presuming you put it in the right scope/didn’t leave a dangling copy.) – Davislor Apr 23 '18 at 03:08

3 Answers3

3

To deallocate an object allocated by new, you should use delete.

To prevent a pointer from being "dangling", set the pointer to nullptr.

Class* c = new Class();
delete c;    // free up the allocated memory from new
c = nullptr; // prevent dangling pointer

if c is not used anymore after destruction, assigning it to nullptr is not needed.

An example why a pointer is set to nullptr after delete is because of null guards like:

if (c != nullptr) {
   delete c;
   c = nullptr;
}

This is redundant since delete already checks if the pointer is still pointing to a valid memory location.

If it is already nullptr, then it does nothing.

From expr.delete#7.3:

Otherwise, the delete-expression will not call a deallocation function.

[ Note: The deallocation function is called regardless of whether the destructor for the object or some element of the array throws an exception. — end note ] If the value of the operand of the delete-expression is a null pointer value, it is unspecified whether a deallocation function will be called as described above.

Community
  • 1
  • 1
Joseph D.
  • 11,804
  • 3
  • 34
  • 67
2

[after setting c=null] object still in the memory and nothing points at it. How we gonna delete it?

You can't -- in that case your program has a type of bug called a memory leak, because without a pointer to the object, you have no way to delete the object you allocated. If you don't want your program's memory usage to grow over time (and potentially exhaust its host computer's RAM at some point), it's important to preserve at least one pointer to each object you have dynamically allocated, precisely so that you can retain the ability to delete the object when you're done using it.

[in the other case] we delete an object, but pointer still points to address location of previous object. In which cases that may be useful?

Having a pointer to a deleted object is almost never useful -- trying to dereference the pointer will cause undefined behavior, and technically even reading the value of the dangling pointer (without dereferencing it) is a no-no as well(!). The only reason not to set the pointer to NULL is because setting the pointer to NULL would take an extra CPU instruction (and an extra write to memory) to perform, and C++ tries not to force you to pay overhead costs that you don't need to pay. So if you can guarantee that you will never try to use the "dangling pointer" after you've deleted the object, it's very slightly more efficient to not set it to NULL than it would be to set it to NULL for no reason.

If all of the above seems a bit programmer-unfriendly to you, you're absolutely right -- it is. Raw pointers demand very exacting behavior from the programmer, and if the programmer doesn't handle them 100% correctly, the result is a buggy program (with memory leaks, or crashes at runtime, or other undefined but undesirable behavior). If you'd prefer to avoid that kind of risk (and you should!) then instead of holding your dynamically-allocated object using a raw pointer (e.g. Class *), you can hold it using a "smart pointer" like std::unique_ptr or std::shared_ptr. The smart-pointer classes will give you the "it automatically does the right thing" behavior that raw pointers do not, at the cost of adding an insignificant amount of overhead to your program.

Jeremy Friesner
  • 70,199
  • 15
  • 131
  • 234
-1

You should delete a pointer before setting it to nullptr. But you do not need to set it to nullptr if you do not use it anymore. In such a case, leaving the pointer dangling (referring to an invalid block of memory) is fine.

But I always prefer RAII which says allocate resources in the constructor and release it in the destructor. It reduces usage of pointers. Then you do not need using pointers for creating an instance of object. Of course this is not always practical but this is a good practice.

// RAII implementation

class ClassA
{
    char *buffer;
public:
    ClassA(): buffer(new buffer[1000])
    {
    }

    ~ClassA()
    {
        delete buffer;
        // now *buffer is invalid (dangling pointer) but it is easy to
        // rely that this invalid code is not called anymore.
    }
}

...

int main()
{
   ClassA instance;
   // here you do not need to use a pointer.
}
Arash
  • 2,114
  • 11
  • 16
  • I believe this isn't related to RAII. This is just a confusion about [dangling](https://stackoverflow.com/questions/17997228/what-is-a-dangling-pointer) pointer. – Joseph D. Apr 23 '18 at 01:07