Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly return a collection of unique_ptr

After changing my code to use unique pointers, I stumbled upon how to return a collection of objects to a client. In general, I want to pass objects as references or non-owning pointers. But if I have a collection of objects, I can't just return the reference to it.

As an example, I have a simple class with a collection of objects, which are all created once and not altered afterwards.

using ObjectUPtr = std::unique_ptr<Object>;
class MyClass
{
  public:
  const std::vector<Object*>& GetObjectsOldStyle() const
  {
    return mObjectsOldStyle;
  }

  const std::vector<VObjectUPtr>& GetObjectsNewStyleA() const
  {
    // I don't like that: The client should not see the unique_ptr ...
    return mObjectsNewStyle; 
  }

  std::vector<VObject*> GetObjectsNewStyleB() const
  {
    // Ok, but performance drops
    std::transform(...); // Transform the collection and return a copy
  }

  const std::vector<VObject*>& GetObjectsNewStyleC() const
  {
    // Ok, only copied once, but two variables per collection needed
    // Transform the collection and cache in a second vector<Object*>
    std::transform(...);
  }

  std::vector<Object*> mObjectsOldStyle;    // old-style owning pointers here
  std::vector<ObjectUPtr> mObjectsNewStyle; // how I want to do it today
}

Today, I usually prefer GetObjectsNewStyleB, but I wonder, if there is a more elegant and efficient way or a general best practice on how to return such collections.

like image 868
badstoms Avatar asked Mar 25 '15 06:03

badstoms


People also ask

What happens when you return a unique_ptr?

If a function returns a std::unique_ptr<> , that means the caller takes ownership of the returned object. class Base { ... }; class Derived : public Base { ... }; // Foo takes ownership of |base|, and the caller takes ownership of the returned // object.

Can unique_ptr be moved?

A unique_ptr can only be moved. This means that the ownership of the memory resource is transferred to another unique_ptr and the original unique_ptr no longer owns it. We recommend that you restrict an object to one owner, because multiple ownership adds complexity to the program logic.

What happens when unique_ptr goes out of scope?

unique_ptr. An​ unique_ptr has exclusive ownership of the object it points to and ​will destroy the object when the pointer goes out of scope.


1 Answers

I would recommend creating your own iterator class. Then create begin and end member functions. You can even overload the dereference operator to return references, instead of pointers (unless your pointers might be null). It might start something like this:

class iterator :
    public std::iterator<std::random_access_iterator_tag, Object>
{
public:
    Object& operator*() const { return **base; }
    Object* operator->() const { return &**base; }
    iterator& operator++() { ++base; return *this; }

    // several other members necessary for random access iterators
private:
    std::vector<ObjectUPtr>::iterator base;
};

It's a bit tedious implementing a standard conforming iterator, but I think this is by far the most idiomatic solution. As mentioned in the comments, the Boost.Iterator library, specifically boost::iterator_facade can be used to relieve some of the tedium.

like image 127
Benjamin Lindley Avatar answered Oct 11 '22 08:10

Benjamin Lindley