Skip to content

Enable get shared from ptr.#221

Closed
DrogonMar wants to merge 1 commit into
LabSound:mainfrom
DrogonMar:enable-shared-this-audionode
Closed

Enable get shared from ptr.#221
DrogonMar wants to merge 1 commit into
LabSound:mainfrom
DrogonMar:enable-shared-this-audionode

Conversation

@DrogonMar
Copy link
Copy Markdown
Contributor

Problem

A lot of functions in LabSound either want the shared_ptr or the raw ptr,
sometimes you only get access to the raw ptr like when traversing the graph and you want to execute some LS function that requires a shared_ptr but currently theres no way to get the shared_ptr from a raw ptr.

Possible solution

Enable std::enable_shared_from_this, I'm not 100% sure if this is a great solution but its been working for me.

Signed-off-by: Reece Hagan <drogonmar@tuyuji.com>
@meshula
Copy link
Copy Markdown
Member

meshula commented Nov 30, 2025

raw pointers are typically used inside the high performance callbacks, and the idea is that they force you to understand that there is no memory ownership of the pointer, and that the pointer must be externally managed.

If you found places where you needed shared but only had raw, it would be worth listing them up for discussion, because basically it means that the "ownership" concept wasn't carried all the way through the implementation.

Did you encounter a lot, or just here and there?

@DrogonMar
Copy link
Copy Markdown
Contributor Author

I've been making a graph GUI for LabSound and when you traverse the graph using the inputs/outputs you just get raw ptr's

auto input = node->input(i);
lab::AudioNode* connectedNode = input->renderingOutput(*renderLock, j)->sourceNode();

at this point your only dealing with raw ptr's and no way to get the shared ptr which kinda breaks using the normal thread-safe connect / disconnect functions from the labsound context.
I dont want to store raw ptr's to nodes since they could become invalid without my Gui knowing so I need to store the shared ptr.

@meshula
Copy link
Copy Markdown
Member

meshula commented Dec 7, 2025

I see. In my graph editor (https://github.com/LabSound/LabSoundGraphToy/tree/main) I don't actually traverse nodes directly, I create a parallel structure (essentially an ECS) that encodes the graph, so unfortunately I haven't got any pattern there you can use. Basically I wrote a life-time context object that owns all the nodes, and the nodegraph asks the context for the nodes. so if a node gets deleted, it is deleted from the context object, and when the graph editor tries to fetch, the context object says "sorry, invalid". the big problem is that nodes have to stay alive until there are no references left in the real time audio callback queue, and it gets really gnarly figuring out when no thread no longer needs a node. that's why there's no shared pointers in the system for nodes at the moment, it's possible to reason about a global scope but it's really hard to reason about threaded scopes that may decrement a reference, or hold a reference past engine shutdown, and so on.

The current scheme is known not to have any concurrency issues versus memory management, assuming all nodes are managed in a context object that outlives the engine (the examples all work that way).

My biggest worry about introducing a shared pointer is that node lifetime needs to be thread safe, and needs to not cause shutdown deadlocks if the engine goes down before the nodes are released.

So I'm not opposed, if we can be confident there are no memory leaks, deadlocks, or double deletes, especially across combinations of engine shutdown, node deletion, and thread terminations.

The idea I had to get past all the issues and be rock solid was to have a big block of memory with the "guts" of the nodes, the big block would be an arena that lives as long as the engine and is completely safe, and the nodes would be allocated slots from the arena. Then there'd be no need to have the nodes in the processing threads at all, and shared pointers would work beautifully. I haven't had time to work this idea through though.

This long note intertwines a bunch of ideas, sorry for the ramble. To your problem, if you have a context object that manages the lifetime of your nodes, you can keep your node lifetimes safe as long as your context object is the only thing that is allowed to create and delete nodes (again, that's the trick in the GraphToy, since it's the only thing that can new and delete it is able to "reap" nodes that it knows are completely unreferenced and no longer in the render queue).

@DrogonMar
Copy link
Copy Markdown
Contributor Author

Seems like enable_shared_from_this isn't as nice as I thought.

I thought it would just return nullptr if the instance wasnt allocated with make_shared but it seems to throw rather than just return null :(

Anyway, I'll prob ditch my current graph system since its more of a debug of whats happening in the labsound context and ill be making an Audio Graph Asset Editor which wont be dealing with labsound node ptr's at all.

I still want a way to traverse the graph and understand what exists while keeping shared ptr's but maybe that could be a new function in context?

@DrogonMar DrogonMar closed this Dec 7, 2025
@meshula
Copy link
Copy Markdown
Member

meshula commented Dec 12, 2025

I think there is a strong need for a traversal routine. If you have a look at what the rendering call back does, it starts at a destination node, and recurses through all the input/output connections to visit all the nodes. It would be very sweet to have a helper function that performs that utility directly. One way to do it would be to introduce a traversal object that is a structure with a pointer to an audio node and a vector of traversal objects in traversal order. Following the data structures directly is complex, it would be great to have a single way to do it.

@DrogonMar
Copy link
Copy Markdown
Contributor Author

Yeah, I'm currently just modifying LabSound as I develop my game and plugin, a lot of my PR's are cherry picks from my personal fork so at some point I'll see about that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants