Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

c++11 member function returns vector of raw pointers from vector of unique_ptr

Tags:

c++

c++11

I am starting using c++11 features and I like to use smart pointers only to own the objects. Here is my class:

class MyClass {
  public:
    vector<MyObject*> get_objs() const;

  private:
    vector<unique_ptr<MyObject>> m_objs;
};

The semantics is that MyClass owns a serial of MyObject which are created through make_unique(). get_objs() returns a vector of raw pointers in order for various callers to update the objects. Because those callers do not own the objects, so the function does not return vector<unique_ptr>.

But this means I need to implement get_objs() like this:

vector<MyObjects*> MyClass::get_objs() const
{
  vector<MyObjects*> ret;
  for (auto obj : my_objs) {
    ret.push_back(obj->get());
  }
  return ret;
}

My concern is get_objs() is called fairly often, each time there is an overhead to construct this raw pointer vector.

Is there something I could do here? If there is no c++11 tricks to save the overhead, should I just use type vector<MyObject*> for m_objs in the first place?

UPDATE 1

Jonathan Wakely's solution using operator[] improves mine so that caller can access individual object directly.

Is there any other solution? I do not mind go over all the places calling get_objs(), but like to see if there is even better solution.

Another note - I cannot use BOOST, just some restriction I have to live with.

like image 624
my_question Avatar asked Aug 26 '14 12:08

my_question


2 Answers

class MyClass {
  public:
   std::vector<std::unique_ptr<MyObject>> const& get_objs() const {
     return m_objs;
   }

  private:
    std::vector<std::unique_ptr<MyObject>> m_objs;
};

a const std::unique_ptr<MyObject>& cannot steal ownership, and is not the same as a std::unique_ptr<const MyObject>. A const std::vector<std::unique_ptr<MyObject>>& can only grant const access to its data.

In c++20 I would instead do this:

class MyClass {
  public:
   std::span<std::unique_ptr<MyObject> const> get_objs() const {
     return {m_objs.begin(), m_objs.end()};
   }

  private:
    std::vector<std::unique_ptr<MyObject>> m_objs;
};

which hides the implementation detail of "I am storing it in a vector" while exposing "I am storing it contiguously".

Prior to c++20, I advise finding or writing your own span type if you have the budget. They are quite useful.

like image 63
Yakk - Adam Nevraumont Avatar answered Oct 28 '22 16:10

Yakk - Adam Nevraumont


For the record, I think something like Jonathan Wakely's answer is the way to go. But since you asked for more possibilities, another one is to use shared_ptr instead of unique_ptr:

class MyClass {
  public:
    const vector<shared_ptr<MyObject>>& get_objs() const {
        return m_objs;
    }

  private:
    vector<shared_ptr<MyObject>> m_objs;
};

This improves the original code in two ways:

  1. There is no longer any need to build up a new vector in get_objs; you can just return a reference to the one you have.
  2. You no longer need to worry about wild pointers in the case where a caller keeps the return value alive longer than the object that returned it--shared_ptr ensures the pointed-to objects aren't deleted until all references have been released.

On another note, get_objs arguably should not be const. Calling code can't modify the vector itself, but it can modify the MyObjects it contains.

like image 35
dlf Avatar answered Oct 28 '22 17:10

dlf