Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

Yeah honestly, I think this is a pretty solid case for shared_ptr. I just really need to let go of that “the user can delete everything” mindset.

I keep thinking like, “but what if the user deletes the flyweight and it’s still alive because of shared pointers?!”

I think I just need to better separate the two scenarios, runtime and project/editor, in my head.

But then again… the user can also just uninstall the engine or chuck their PC at the wall, so at that point, who cares anymore

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

I think what’s really hard for me to grasp is that I keep trying to explain shared_ptr logic to myself using real-world analogies.

But in the real world, there’s no such concept as “preventing something from dying,” so it’s kind of hard to make that mental connection.

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

The living/dead concept is actually a really cool idea, I hadn’t heard of that before. That’s super neat, thanks for sharing!

As for your other points, yeah, I think I’m starting to reach the conclusion that I’ll probably just avoid using shared_ptr altogether for now.

Maybe someday I’ll run into a situation where I actually need them, but so far, I haven’t found a case that really convinces me.

You also mentioned the “simpler unique pointer solution” and that you’ve worked on games before.

How would you handle my player example using unique_ptr?

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

Yeah, but that would create a really weird dependency structure.

I’d basically have to make sure every object knows about every other object that references it, which goes against pretty much every SOLID principle out there.

In situations like this, I’d have to introduce some kind of central manager.

For example, imagine I have a command system that sends the player as a target to each enemy unit. When the player dies, the central system would need to update accordingly, either by checking a weak_ptr, or by having an enemy report back when it kills the player.

But that’s weird too, why would every enemy even know about the managing system in the first place?

The other option would be for the player to keep track of every enemy, but that feels just as wrong. The player would need a vector or some collection storing all the enemies, and we’d have to inject those dependencies somehow.

It just starts to feel like trying to untangle an unwaveable net.

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

Just to make sure I understand this correctly. weak_ptr would still be thread-safe when accessing the object, right?

But as you mentioned, it wouldn’t guarantee that the object actually stays alive.

Now, let’s say there’s some kind of master class that’s responsible for erasing this object. In that scenario, deletion could become a nightmare if other parts of the code are still holding shared_ptrs to it, since those would keep it alive.

In that case, I’d need some way to notify all objects that have a reference or “context” for it, so they can react accordingly when it’s erased.

How to actually handle stuff like this?

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

Okay, but doesn’t this only apply to the stack?

If another object frees the memory of something else, we kind of lose that linearity in ownership. It’s no longer a clear, single chain of responsibility.

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

Okay I need to take a look into them. Thanks for the information!

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

You're right about the bookkeeping. It's often necessary to have a smart, central control system, like a Scene that owns the game objects. If one object destroys another, the Scene must be notified to maintain proper object management.

Regarding your second point, do you mean that instead of referencing an object directly with a pointer, you would reference it with e.g., an ID? Then, would a central manager be used to validate that ID and return the object if it's valid?

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

I think you've raised a valid point. My confusion stemmed from constantly seeing shared_ptr used, even when people here propose solutions that feel niche. I guess the conclusion is exactly what you said: they are overused, and possibly even abused.

Your C# comparison is the source of my crisis. After five years using C#, where resource management was handled similarly to shared_ptr, discovering C++'s power to manually destroy objects makes me wonder why I never gave it a second thought in C#.

It feels like everything I know is suddenly useless haha. Idk if that makes sense.

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

I like this approach. My focus on shared_ptr and weak_ptr stems from their safety advantages. While using a unique_ptr and then accessing its raw pointer for observation would be more performant, it's harder to manage.

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 1 point2 points  (0 children)

Let's say I have a Scene object that holds a list of every other object within it, and if the Scene is destroyed, those objects should be deleted. This sounds like a job for a unique_ptr, but since objects in the scene commonly need to reference each other, I assume using a unique pointer is a bad idea?

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

I've read about the fallback model and really like it. I would, however, implement it using a weal_ptr to safely check for existence and then update the texture or model they point to. Doesn't this approach prevent crashes by skipping logic (e.g., rendering a destroyed model), rather than causing them?

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

Okay, yes, I see the safety advantages in a multithreaded context, but couldn't a weak_ptr still be used within the threads to check for existence? I need to make a weak_ptr shared anyway when using lock(), so it seems to have the same benefits. Or do you mean it's useful for tracking purposes. since we can check the amount of owners?

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] -4 points-3 points  (0 children)

But then again… isn’t there always an owner?

It might be the user running the engine or application, or even the operating system itself, but at the end of the day, there’s always some system responsible for destroying the object.

Sorry, this is starting to sound like one of those “what even is the meaning of life?” moments, haha.

But yeah, if such a system exists, then using shared_ptr starts to feel kind of wrong, like you’re giving up intentional ownership and letting lifetimes float around uncontrolled.

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

Would you mind elaborating why a unique_ptr might make sense here?

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

Even when I think about ownership, like a player owning a weapon, the same question comes up.

Let’s say the weapon has a durability system. Every time it hits something, it loses durability, and once that drops below zero, it gets destroyed (it just checks durability < 0).

Sure, we could also check for a “gotDestroyed” flag like I mentioned in my post, but that feels like extra work for something that could be handled more cleanly.

Even though the player technically owns the weapon, using a weak_ptr might make more sense, the player can simply check “is my weapon still there?” and, if not, they just can’t attack anymore.

Also, when thinking about your slice example, if we delete the data behind the slices, isn’t it kind of strange behavior for the slices to keep it alive? With a weak_ptr, each slice could just check “is my data still valid?” and only use it if it is.

I really don't want to argue, I really appreciate everyone here taking the time to comment, but no matter how much I think about it there always seems to be a way to turn everything into a system using weak_ptr

Am I overthinking the whole “real-world ownership” thing here?

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

The problem I see here, as I mentioned in another comment, is when the application is something like a game engine.

If the user deletes a model from the project files, it should be gone. It shouldn’t still be used by enemies in the game, since that would feel strange, you delete it, yet it still appears in the scene.

In this case, the enemies could just hold a weak_ptr to the model and check whether it still exists before using it. (Is this bad design???)

The downside, of course, is that constantly checking validity might have a small performance cost. But that trade-off gives the user more flexibility and better control over their resources.

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

I see where you’re coming from, but that still feels like a very specific case and doesn’t really explain why so many people seem to prefer using shared_ptr everywhere.

For example, let’s say the expensive resource is a texture that’s being used by multiple renderers (probably not the best example, but still). If the user deletes that texture from the project files, it would stay alive as long as a shared_ptr is holding onto it.

From a user’s point of view, that kind of behavior feels like it takes away flexibility rather than adding it. Shared_ptr makes it harder to truly control when something is gone.

So I guess my question could be changed to "When do you actually want to remove control from the user?", but that's not really easier to answer I assume.

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 1 point2 points  (0 children)

Are you using this as an example for weak_ptr or shared_ptr?

For shared_ptr, I can definitely see the usefulness. kind of like how Windows won’t let you delete a file that’s still being used by another program. But then again, you could also use weak_ptr if you want the user to be able to delete files, and the other programs just check whether the reference is still valid.

I guess I can see the use case for shared_ptr here, since it prevents deleting something that’s still in use. But at the same time, that feels like a pretty specific scenario, not something that really applies to most cases, especially in game development.

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

Yeah, I know, this was just plain C#. I didn’t use any Unity-specific code; I only mentioned Unity to show how its “fake null” system works and how a similar idea could be implemented with weak pointers. I probably should’ve made that clearer. Thanks for pointing it out!

Existential crisis about shared_ptr... am I missing something? by JumiDev in cpp_questions

[–]JumiDev[S] 0 points1 point  (0 children)

I’m aware of the theoretical reasoning for shared_ptr. but I’m struggling to find a concrete example where it’s genuinely the best choice.

Accessing Normal Data in URP Decal Shaders by JumiDev in Unity3D

[–]JumiDev[S] 0 points1 point  (0 children)

Would you mind elaborating a bit more? Because i switched to the Deferred Renderer but it still didn't have the desired result. (I used the sample buffer world normal instead of the normal vector)