3

I have an object:

class Object {
public:
  boost::shared_ptr<QString> const& name() const {reutrn _name;}
private:
  boost::shared_ptr<QString> _name;
};

And a multi_index set

typedef
    boost::multi_index_container<
        Object,
        boost::multi_index::indexed_by<
            boost::multi_index::ordered_unique<
                boost::multi_index::const_mem_fun<
                    Object,
                    boost::shared_ptr<QString> const&,
                    & Object::name>,
                StringPointerLess> > >
    ObjectSet;

Now If I want to find something in the set and I have QString I need to make a copy of it to allocate in heap and create shared_ptr.

Is it possible to avoid this unnecessary copy operation, leaving the set as it is?

Richard Cook
  • 32,523
  • 5
  • 46
  • 71
user14416
  • 2,922
  • 5
  • 40
  • 67
  • Are you sure you've got the definition of `ObjectSet` right? By indexing on `boost::shared_ptr`s, two elements are considered equivalent if their `name` members point to the same string, *not* if the strings they point to are equal. – Joaquín M López Muñoz Mar 05 '13 at 18:20
  • For this I have `StringPointerLess`. – user14416 Mar 05 '13 at 20:03

2 Answers2

3

A simpler way: add the following member functions to your StringPointerLesscomparison predicate:

struct StringPointerLess{
  ...
  bool operator()(boost::shared_ptr<QString> const& x,const QString& y)const{
    return *x<y;
  }
  bool operator()(const QString& x,boost::shared_ptr<QString> const& y)const{
    return x<*y;
  }
  ...
};

and now you can lookup by simply providing the desired QString:

IteratorType find( MyContainerType const& container, QString const& key )
{
   return container.find( key );
}

The magic behind this is explained at the special lookup operations section in Boost.MultiIndex documentation.

Joaquín M López Muñoz
  • 5,243
  • 1
  • 15
  • 20
1

Yes, you still have to make a shared_ptr but you can use a custom-deleter that does not delete your object, and then pass it in as a pointer from the stack.

Of course one of your issues is that your shared_pointer is not to const, so if you have a const QString & you either have to duplicate it or const_cast. I will do the latter but leave it up to you what to do.

We don't want to do that everywhere we pass in a QString so let's write a function:

struct no_op_functor
{
 public:
   template< typename T > operator()( T* ) const
   {
   }
};

IteratorType find( MyContainerType const& container, QString const& key )
{
   boost::shared_ptr< QString > keyShared( const_cast<QString *>(&key), no_op_functor() );
   return container.find( keyShared );
}
CashCow
  • 30,981
  • 5
  • 61
  • 92