Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: A question about shared_ptr (not strictly sfml specific)  (Read 2628 times)

0 Members and 1 Guest are viewing this topic.

Critkeeper

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
A question about shared_ptr (not strictly sfml specific)
« on: January 15, 2015, 01:45:08 am »
I had this idea bout using shared_ptr to keep a single object alive while multiple pointers point to it, namely resource type objects like textures and sound effects and even ai scripts.

Imagine having a arcade shooter scene and you have a bunch of the same kind of vessel floating around. With shared_ptr they can all access the same resources, the sprite, the sound effects, etc, for that specific kind of vessel. Thats great, and thats what we want.

And when the last vessel of a particular kind is destroyed and we don't see another of that type for 5 minutes, then it is unloaded from memory. Thats fine too.

What if we are in a situation where we require a single pointer to particular resource and no more, intermittently over a period of time? For example if we have one vessel of a particular type that requires access to a particular set of resources, textures, sounds, etc, and we only ever have one in the scene at a time, but every time it is destroyed it respawns after a second or so. It would be wasteful to unload and reload it from memory over and over.

So in order to get around that we would want to tell the shared_ptr implementation to not delete the resource object when it hits a count of zero referring vessel objects (or preferably, to just increment the count by 1 and change nothing else). However, I cannot access the reference count directly in order to modify it-- its a private member of the shared_ptr implementation. The only recourse I can think of is to create "dummy" pointers that are only used to keep the count one higher than it would otherwise be, and therefore keep the resources in memory so that they do not need to be reloaded.

Seems ugly though. A person reading code who sees a pointer expects it to be used for something other than keeping the reference count of a shared pointer 1 higher than it would otherwise be. Is there a better way to do this that is no more complicated?

EDIT:

As I think about it though, if there are no references to the object how can i know how to dereference it in the first place? I guess the "dummy" pointer would really be a kind of codeless pointer factory.
« Last Edit: January 15, 2015, 01:55:08 am by Critkeeper »
if(CritKeeper.askQuestion()){return question.why();}

Ixrec

  • Hero Member
  • *****
  • Posts: 1241
    • View Profile
    • Email
Re: A question about shared_ptr (not strictly sfml specific)
« Reply #1 on: January 15, 2015, 01:56:51 am »
As far as I know, everything you describe is supported by the ResourceCache in Thor: http://www.bromeon.ch/libraries/thor/v2.0/tutorial-resources.html

The ResourceCache itself owns the resources, so by default they don't get freed until the whole cache goes out of scope.  You can call release() to manually release individual resources (if no one other than the cache is using them), or set the cache to AutoRelease mode to make it automatically release resources that aren't getting used.  And there's nothing stopping you from making multiple caches so that certain resources get one policy and other resources get another, which is probably the clean solution to your problem.

It does all this with shared_ptr, but without the massive hack you're proposing =)
« Last Edit: January 15, 2015, 01:58:30 am by Ixrec »

grok

  • Jr. Member
  • **
  • Posts: 67
    • View Profile
    • Email
Re: A question about shared_ptr (not strictly sfml specific)
« Reply #2 on: January 15, 2015, 06:03:54 am »
Have a (single) instance of ResourcesManager class which keeps your resources being wrapped in shared_ptr in the map and loads/returns them on demand (still wrapped in shared_ptr). In this case the resource won't be deallocated unless it is released from
1) all places where it was stored (your game objects)
2) the ResourcesManager's map

If you really want to have that map delete your resources, you might add "deleteResource" method to it.
In this case if you're absolutely sure there're only two instances of shared_ptr floating around, for example, the one stored in some GameObject instance and the second lying in the ResourcesManager map, if you delete it from the both places, it will be freed.
If it is released from all you GameObjects (having the same resource, wrapped into shared_ptr), but stlll present in the ResourcesManager's map, it won't be deallocated.

Hope that helps.
« Last Edit: January 15, 2015, 06:45:57 am by grok »

Critkeeper

  • Jr. Member
  • **
  • Posts: 62
    • View Profile
Re: A question about shared_ptr (not strictly sfml specific)
« Reply #3 on: January 16, 2015, 01:11:45 am »
Hope that helps.

It does, thanks. I've already come up with a solution not much different than the one you are suggesting though. I'm going to have a ResourceHolder class that has 3 methods.

shared_ptr< resource > get( id )
void keep( id )
void unkeep( id )

it has 2 private members

map< id, string filename > disk
map< id, shared_ptr< resource > > memory

when asked to get( id ) the object will look inside of memory to see whether or not an id with the requested value exists, and if it does it will return a shared_ptr with the same value. If not, it will load from memory the resource requested using the information in the member disk, and it will return a shared_ptr to that resource as the return value of get( id ). It will NOT store a second shared_ptr in the member memory.

In order to manually tell the object to not release a resource from memory you must tell it to keep it in memory using keep( id ), which just creates an (id, shared_ptr) pair inside of the map member memory. Unkeep undoes the operation.

Does the theory of this look sound, or is there something I might be missing?
if(CritKeeper.askQuestion()){return question.why();}