microsoft / cppwinrt

C++/WinRT
MIT License
1.64k stars 236 forks source link

Ability to remove built-in reference counting from a implementation type #1360

Closed JaiganeshKumaran closed 9 months ago

JaiganeshKumaran commented 11 months ago

Currently every WinRT implementation type inheriting from implements automatically gets reference counting implemented. While you could override AddRef and Release, you still get the reference count field which cannot be removed. In some scenarios, you might want to eliminate the reference count field and do it all manually. These might include:

I propose adding a new marker type, winrt::no_ref_count which will remove the ref count field, as well as the default implementations of AddRef and Release.

kennykerr commented 11 months ago

I've tagged a few project maintainers. If one of them is available to offer guidance and mentorship for this issue, they will reach out according to the contributing guide to discuss and agree on an approach.

@microsoft/cppwinrt-maintainers

FWIW the implements class template is terribly complicated already. I would recommend you simply use your own fork for such dramatic customizations.

oldnewthing commented 11 months ago

Overriding AddRef and Release are not sufficient because m_references is also used for weak reference support.

Even static lifetime objects need to implement AddRef and Release so they can tear down at COM uninitialization. Otherwise, you get bugs where the DLL is unloaded (DllCanUnloadNow) because it lost track of its static lifetime objects.

JaiganeshKumaran commented 11 months ago

Otherwise, you get bugs where the DLL is unloaded (DllCanUnloadNow) because it lost track of its static lifetime object

Well I can prevent unload and have it has a pinned DLL.

JaiganeshKumaran commented 10 months ago

Currently I have complex cyclic object relationship where both objects must be alive at simultaneously. Weak references won't in my case because once get destructed while the other is alive. Having this feature would be really helpful so I can use a shared ref count for the two objects. Without it, I'm forced implement the ABI interfaces (or inherit from impl::produce<Derived, Interface>), without the help of winrt::implements.

oldnewthing commented 10 months ago

The WindowsAudioSession sample had a similar issue, which it solved by using embedded objects, although in the WindowsAudioSession case, it was clear which object was "primary" and which was "ancillary".

Another solution is to make the two objects explicitly one object under the hood, so their lifetimes are naturally coupled.

struct WidgetState
{
 // Widget business logic goes here
};

struct DoodadState
{
 // Doodad business logic goes here
};

struct CommonState
{
    WidgetState widgetState;
    DoodadState doodadState;
};

struct Widget : WidgetT<Widget>
{
    std::shared_ptr<CommonState> const m_state;
    Widget(std::shared_ptr<CommonState> const& state) : m_state(state) {}

    void WidgetMethod1() { return m_state->widgetState.WidgetMethod1(); }
    void WidgetMethod2() { return m_state->widgetState.WidgetMethod2(); }
};

struct Doodad : DoodadT<Doodad>
{
    std::shared_ptr<CommonState> const m_state;
    Doodad(std::shared_ptr<CommonState> const& state) : m_state(state) {}

    void DoodadMethod1() { return m_state->doodadState.DoodadMethod1(); }
    void DoodadMethod2() { return m_state->doodadState.DoodadMethod2(); }
};

std::pair<winrt::Widget, winrt::Doodad> MakePairedWidgetAndDoodad(Args args)
{
    auto state = std::make_shared<CommonState>(args);
    return { winrt::make<Widget>(state), winrt::make<Doodad>(state) };
}

Now you have a Widget and a Doodad whose lifetimes are coupled. Even if the app releases the last Widget, the WidgetState will remain alive until they also release the last Doodad.

github-actions[bot] commented 10 months ago

This issue is stale because it has been open 10 days with no activity. Remove stale label or comment or this will be closed in 5 days.

JaiganeshKumaran commented 10 months ago

@oldnewthing I don't want to have state separately; I want the sub-object itself to be alive. The embedded object solution is what I'm trying to do but implementing ABI interfaces directly is tedious, which is why I want winrt::implements to allow customisation of reference counting.

github-actions[bot] commented 10 months ago

This issue is stale because it has been open 10 days with no activity. Remove stale label or comment or this will be closed in 5 days.