2

I have two classes: an Object class, and an ObjectManager class. The ObjectManager class stores "Objects" via a ptr_vector container. There are some instances where I need to retrieve references to these stored pointers to perform individual actions on them. How would I go about doing so?

Compilable Pseudo Code:

#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/shared_ptr.hpp>

class Object
{
public:
  int m_Id;
  Object(int id) : m_Id(id) { }
};

class ObjectManager
{
private:
  typedef boost::shared_ptr<Object> ObjectPtr;
  typedef boost::ptr_vector<Object> ObjectVectorPtr;
  typedef ObjectVectorPtr::iterator ObjectIt;

  ObjectVectorPtr vector_;

  void AddObject(Object *obj) {
    vector_.push_back(obj);
  }

  ObjectPtr FindObject(int id) {
    for (ObjectIt it = vector_.begin(); it != vector_.end(); it++) {
      if (it->m_Id == id) {
        // Found the object...How to return a shared_ptr reference to it?
        // The line below is invalid, obviously:
        // cannot convert parameter 1 from 'Object' to 'const boost::shared_ptr<T> &'
        return *it;
      }
    }

    // We could not find anything.
    return ObjectPtr();
  }
};

Basically I want the ObjectManager to retain ownership, but I also want other classes to be able to get a reference to the object, use call methods on that object depending on what's going on, and move on.

jbaez
  • 391
  • 3
  • 9

2 Answers2

2

Convert your container to use shared_ptr as the member:

#include <boost/ptr_container/ptr_vector.hpp>
#include <boost/shared_ptr.hpp>
#include <vector>

class Object
{
public:
  int m_Id;
  Object(int id) : m_Id(id) { }
};

class ObjectManager
{
private:
  typedef boost::shared_ptr<Object> ObjectPtr;
  typedef std::vector<ObjectPtr> ObjectVectorPtr;
  typedef ObjectVectorPtr::iterator ObjectIt;

  ObjectVectorPtr vector_;

  void AddObject(ObjectPtr& obj) {
    vector_.push_back(obj);
  }

  ObjectPtr FindObject(int id) {
    for (ObjectIt it = vector_.begin(); it != vector_.end(); ++it) {
      if (it->get()->m_Id == id) {
        // Found the object - return a shared_ptr reference to it
        return ObjectPtr(*it);
      }
    }

    // We could not find anything.
    return ObjectPtr();
  }
};

btw - prefer ++it vs it++ to avoid extra construction, and don't use matching like this if the container gets large - switch to std::map<int, ObjectPtr> with m_id as the key, or std::set with suitably-defined less function.

If I was being super-pedantic I would suggest replacing your find loop with a call to std::find_if, with a predicate that matches on Object::m_id...

Steve Townsend
  • 53,498
  • 9
  • 91
  • 140
  • Ahh, thanks Steve! Also, if you don't mind answering, when you said "don't use matching like this if the container gets large," are you referring to performance issues? – jbaez Sep 21 '10 at 23:08
  • @jbaez : yes this is perf-related - matching like this will be O(n) - searching map (binary tree) is O(log n) – Steve Townsend Sep 21 '10 at 23:11
0

You can't return a shared_ptr because the object wasn't created as a shared object initially - what would the reference count even be?

You can, however, return an Object* quite easily:

Object* FindObject(int id) {
    for (ObjectIt it = vector_.begin(); it != vector_.end(); it++) {
      if (it->m_Id == id) {
        // Found the object...How to return a shared_ptr reference to it?
        // The line below is invalid, obviously:
        // cannot convert parameter 1 from 'Object' to 'const boost::shared_ptr<T> &'
        return &*it;
      }
    }
Nicholas M T Elliott
  • 3,643
  • 2
  • 19
  • 15