Conventions for dealing with vectors of std::tr1::shared_ptr

178 views Asked by At

I've started using std::tr1::shared_ptr and so far I'm quite liking it. I understand some of the pitfalls (e.g. two classing containing smart pointer members to each other). But there are other cases which I'm unsure about whether to use smart pointer or not.

E.g.

class Scene;
typedef shared_ptr<Scene> ScenePtr;

Class SceneManager {
public:

   int size() { return _scenes.size(); }
   ScenePtr scene(int i) { return _scenes[i]; }

private:
   vector<ScenePtr> _scenes;
}

This is all good and working nicely. However, if I have an external controller, is there any disadvantage of doing:

for(int i=0; i<_sceneManager->size(); i++) {
   ScenePtr scene = _sceneManager->scene(i);
   scene->doSomething();
}

here 'scene' will obviously increase the reference count of each ScenePtr, but then decrease it again when it goes out of scope. But is there any performance (or any other) disadvantage?

Alternatively I could use a normal C pointer

for(int i=0; i<_sceneManager->size(); i++) {
   Scene* scene = _sceneManager->scene(i).get();
   scene->doSomething();
}

But is this actually any better? or is it identical? Does the reference count get increased? (on the function call), but then decreased as soon as it leaves the first line?

I often used to use a reference, would that have any complications?

for(int i=0; i<_sceneManager->size(); i++) {
   Scene& scene = *_sceneManager->scene(i);
   scene.doSomething();
}

And finally, is it even a good idea to return a ScenePtr at all, or should SceneManager::scene(i) return a (Scene*) or even (Scene&)?

Similarly, to do an ordered map I often used to use: vector _scenesArray; map _scenesMap;

So I can access the objects by name, or in order. Using std::tr1::shared_ptr should they both be ScenePtr? or just one of them ScenePtr and the other one Scene*?

1

There are 1 answers

0
PeterSW On

It all depends on the use cases.

As you suspect using the pointer or reference will save on the reference counting overhead.

...but... often the overhead isn't significant enough to worry about and:

If the sceneManager is used in multiple threads or this function needs to be reenterent safe then the safety of accessing though the shared pointer might be preferred. As in if you're not using the shared_ptr you need somehow else to be sure the object won't be destroyed.

What to return depends on if the ownership of the object is to be passed on. You must not go from a pointer to shared_ptr if the object is already in a shared pointer somewhere else. You have to pass from shared_ptr to shared_ptr or each separate chain of shared_ptrs will try to delete the object. Multiple deletion => crash.

If ownership is staying with the SceneManager then returning a reference would give easy use of the object and express the ownership intension clearly.

Similarly, to do an ordered map I often used to use: vector _scenesArray; map _scenesMap;

For simplicity and flexibility I'd start with them both holding shared_ptrs. If later in the unlikely situation that turns out to be a bottle neck in the application you can swithc and add logic as a performance optimization.