Pass std::shared_ptr in DragAndDrop?

Hi everyone,

Currently I’m trying to implement some DragAndDrop behaviour using the JUCE built-in classes. However, startDragging(var &sourceDescription, Component *sourceComponent) requires me to pass a description of the dragged object as a “var”. However, I would much rather pass a std::shared_ptr, as that is what I’m using internally everywhere. std::shared_ptr seems incompatible with the ReferenceCountedObjects, which can be passed as a var. Does anyone know of a way to do this? Thanks in advance for your replies!

shared_ptr offers the same functionality as ReferenceCountedObject::Ptr. So that would be one workaround.
Out of bitter experience I would use shared_ptr with extra care, since reference cycles can lead to improper shutdowns, and several other fun. I use it for data models, but never for Components.

For drag and drop I always hoped for a way to add the SharedObject of a ValueTree into a var, but that needs some hackery. The SharedObject is not directly accessible. Either we need an overload for var (ValueTree&) and back, or a method ValueTree::getSharedObject(), but I doubt they want to expose that internal thing.

I solved that problem in some occasions by using the originalComponent in the DragDescription and pick the selected element from there. It’s not really a clean way, but effective for time being.

You can do it by wrapping the shared_ptr into a ReferenceCountedObject:

namespace juce {
template<typename T>
struct VariantConverter<std::shared_ptr<T>>
{
    static std::shared_ptr<T> fromVar(const var& v)
    {
        if (auto* wrapper = dynamic_cast<SharedPtrWrapper*>(v.getObject()))
            return wrapper->ptr;

        return nullptr;
    }

    static var toVar(const std::shared_ptr<T>& s)
    {
        return new SharedPtrWrapper(s);
    }

private:
    struct SharedPtrWrapper final : ReferenceCountedObject
    {
        SharedPtrWrapper(const std::shared_ptr<T>& ptr)
        : ptr(ptr) {}

        const std::shared_ptr<T> ptr;
    };
};
}

// Usage
using Converter = VariantConverter<std::shared_ptr<int>>;
var myInt = Converter::toVar(std::make_shared<int>(42));
jassert(*Converter::fromVar(myInt) == 42);

But using ReferenceCountedObject directly is cleaner IMO.

1 Like

Thank you, the VariantConverter works like a charm!

Still I think there would be several valid reasons for using a shared_ptr right? I’m mainly thinking interfacing with third-party libraries. Or the fact that a normal object can be used as an object and by using a shared_ptr in different places, while a ReferenceCountedObject is, well, always ReferenceCounted?