SafePointer Question


#1

I notice that when calling delete on a SafePointer, that the Component in memory is deleted and the pointer is set to NULL. I assume this is the whole point of this class, however, my question is, what is the difference between using delete or using the method deleteAndZero()? Am I misunderstanding something, or are they equivalent here? If they are equal, I assume the method is there to just avoid using the delete keyword?


#2

The SafePointer object allows you to check whether someone else (i.e. another function) has deleted the contained pointer. It also allows you to delete the pointer using the deleteAndZero() method.

Here’s a use-case:

auto *myComponent = new MyComponent();
SafePointer<MyComponent> safePointer(myComponent);

maybeDelete(myComponent); // this function may or may not delete the pointer

if (safePointer.getComponent() == nullptr) {
    // the pointer was deleted by maybeDelete
} else {
    safePointer.deleteAndZero(); // delete the pointer
    // you could alternatively call:
    delete myComponent;
    // which has exactly the same effect, but perhaps you only have the SafePointer object and not the raw pointer here.
}

#3

They are equivalent. The deleteAndZero() method is a relic, when SafePointer was a bespoke solution for Components. It was replaced a long time ago to use a WeakReference internally.


#4

Right, I’m using the SafePointer currently to manage a pop-up window that follows the JUCE code examples exactly for JUCE windows. When the window exit button is clicked, delete is called on this, referring to the window, and I also provide another way to close the same window from the main application, which follows your if-else code almost exactly, only my question was if it is okay to use delete directly on the SafePointer itself, not the object it points to. I wasn’t sure if using delete directly on the SafePointer was safe and equivalent to using the deleteAndZero() method or not.


#5

Great, so it seems I can treat it like a typical pointer and use delete directly on the SafePointer, and it will handle the deleting the associated memory and setting itself to NULL.


#6

Yes, deleting the SafePointer’s pointee will cause the wrapped WeakReference to be set to nullptr from the pointee’s destructor. And all synchronously.


#7

But if you call delete on the SafePointer, do you actually have a SafePointer*? That doesn’t seem logical to me.

Just so I understand correctly - in my example, would you call delete safePointer or delete myComponent?


#8

Yes I’m calling delete on the SafePointer. It was something I did instinctively (without any thought) as I wrote the code originally a year or more ago, before I even know of the deleteAndZero() function. I just assumed it would work fine.

To be honest with you, I never call delete on the item that a pointer is pointing to, I always call delete on the pointer itself, like I would with a standard raw C++ pointer. I’m not entirely sure I follow why you are suggesting this is wrong, but I don’t pretend to fully understand the JUCE pointer classes and how they work internally, so I assume the error is on my end.


#9

It’s certainly not an error, it’s just not something I’m used to seeing when working with smart pointers :slight_smile: In any case, as @daniel said, both are fine.


#10

I think you are correct. Most people who use smart pointers use them for whatever advantage they may offer (scoped or safe pointer) on top of being able to avoid using the keywords ‘new’ and ‘delete’, so it does seem odd that I mixed in a keyword typically used with a raw C++ pointer.


#11

If you are however calling delete on the SafePointer object (i.e. not a SafePointer*) without having allocated it using new before, you are in violation of the rules of the delete operator. delete is only supposed to be used on pointers you created on the heap. Can you show me a code snippet, as I’m still not sure what exactly you’re doing?


#12

I think, there is some confusion. You should be concerned about ownership of the object. The SafePointer doesn’t own the object, so it’s lifetime is not defined by the SafePointer. If you use the SafePointer like a raw pointer, you are not following the RAII principles and risk memory leaks. The SafePointer only helps against dangling pointers, which is a start, but not the whole nine yards.

Have a look at CPP-reference.com: RAII and std::unique_ptr


#13
void MainComponent::buildInformationWindow()
{
    // Don't allow multiple copies of this window to be made
    if (basicWindow == nullptr)
    {
        basicWindow = new BasicWindow ("Information", Colours::grey,
                                       DocumentWindow::closeButton |
                                       DocumentWindow::minimiseButton);

        basicWindow->setUsingNativeTitleBar (true);
        basicWindow->setContentOwned (new InformationComponent(), true);

        const int centerOfThisComponentX = getScreenPosition().x + (getWidth() / 2);
        const int centerOfThisComponentY = getScreenPosition().y + (getHeight() / 2);
        basicWindow->setCentrePosition (centerOfThisComponentX, centerOfThisComponentY);

        basicWindow->setVisible (true);
    }

    else
        delete basicWindow;
}

#14

I also call ‘delete this’ inside the actual window class itself when the exit button is clicked.


#15

What type is basicWindow? Is it Component* or SafePointer<Component>?


#16

SafePointer < Component >

Sorry, iPhone typing isn’t working out with the code formatting

And I realize what you are asking now, no, I don’t have a SafePointer*, it’s just a SafePointer < Component > that I’m using delete directly on.


#17

In that case, your code is certainly very strange.
It’s not possible to delete a non-pointer object using the delete operator, see https://stackoverflow.com/questions/4355468/is-it-possible-to-delete-a-non-new-object

The reason I imagine this works, is that the SafePointer is implicitly converted to the contained pointer when calling the delete operator, as the SafePointer exposes an operator ComponentType*().

In any case, don’t do that. Please call deleteAndZero() on the SmartPointer object.


#18

Why do you deem this necessary? In my experience, one pretty much never has to delete this.


#19

Interesting. Yeah I checked the JUCE API just now and saw no delete operator defined for it, so it must be working because of the coincidence you’ve outlined.


#20

The whole ‘delete this’ is actually suggested in the example code I found in JUCE.