3

I have a collection (currently boost::ptr_vector) of objects (lets call this vec) that needs to be passed to a few functors. I want all of the functors to have a reference/pointer to the same vec which is essentially a cache so that each functor has the same data cache. There are three ways that I can think of doing this:

  1. Passing a boost::ptr_vector<object>& to the constructor of Functor and having a boost::ptr_vector<object>& member in the Functor class

  2. Passing a boost::ptr_vector<object>* to the constructor of Functor and having a boost::ptr_vector<object>* member in the Functor class

  3. avoid the use of boost::ptr_vector and directly pass an array (object*) to the constructor

I have tried to use method 3, but have been told constantly that I should use a vector instead of a raw pointer. So, I tried method 2 but this added latency to my program due to the extra level of indirection added by the pointer. I am using method 1 at the moment, however I may need to reassign the cache during the lifetime of the functor (as the data cache may change) so this may not be an appropriate alternative.

Which I don't fully understand. I assume somewhere along the way the functor is being copied (although these are all stored in a ptr_vector themselves).

Is method 3 the best for my case? method 2, is too slow (latency is very crucial), and as for method 1, I have been advised time and again to use vectors instead.

Any advice is much appreciated

Aly
  • 15,865
  • 47
  • 119
  • 191
  • Could you have forgotten a `*` in a signature when switching between methods? – Constantin Nov 14 '12 at 16:06
  • @Constantin that was it, removing the error from the question and making it more general about which method I should use – Aly Nov 14 '12 at 16:13

1 Answers1

2

A reference in C++ can only be initialized ('bound') to a variable.

After that point, a reference can not be "reseated" (made to refer to a different variable) during it's lifetime.

This is why a default copy constructor could conceivably be generated, but never the assignment operator, since that would require the reference to be 'changed'.

My recommended approach here is to use a smart pointer instead of a reference.

  • std::unique_ptr (simplest, takes care of allocation/deallocation)
  • std::shared_ptr (more involved, allows sharing of the ownership)

In this case:

std::shared_ptr<boost::ptr_vector<object> > m_coll;

would seem to be a good fit

sehe
  • 374,641
  • 47
  • 450
  • 633
  • Ahh, it definitely will need to be reseated as the data cache could change. If I use a shared_ptr, how do I pass it to the constructor? as a reference (shared_ptr<...>&), if so during the assignment will it not make a copy of this object? – Aly Nov 14 '12 at 16:12
  • @Aly pass the shared_ptr by value. – juanchopanza Nov 14 '12 at 16:16
  • @Aly by value or by reference should both work equivalently. In fact, depending on the actual scenario there is some contention as to what variant would allow the compiler to generate the most optimal code (See a published Q&A interview where Herb Sutter and Andrei Alexandrescu answered this question and some blog posts). In this case, I'd write the intent, which is 'pass-by-reference' – sehe Nov 14 '12 at 16:16
  • @juanchopanza Highlighting my point ^ ["Want Speed, Pass By value"](http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/) (D.Abrahams) comes to mind. Let me see whether I can find the Q&A video link. – sehe Nov 14 '12 at 16:17
  • @juanchopanza However, this is still a pointer and will have the added latency that using an array would not correct? – Aly Nov 14 '12 at 16:18
  • @sehe if I pass by value, each Functor will have a copy of the shared_ptr object, but all of them will share the same underlying pointer, correct? – Aly Nov 14 '12 at 16:19
  • @Aly that (the pointer overhead) is unrelated. The use of the smartpointer here is ["Rule Of Zero"](http://rmartinho.github.com/2012/08/15/rule-of-zero.html): getting the ownership semantics correct. If that is not of concern, then by al means, pass a raw pointer. – sehe Nov 14 '12 at 16:20
  • @sehe Oh I see so I could use a shared_ptr to an array (insead of the vector), which would be equivalent to obj* (raw pointer) but with cleanup handled for me? But if I used shared_ptr of vector this is equivalent to vector* which adds that layer of indirection that I dont want – Aly Nov 14 '12 at 16:23
  • @Aly one solution could be to pass an `std::ref` or `boost::ref` instead. This should avoid the assignments. – juanchopanza Nov 14 '12 at 16:23
  • @juanchopanza I'm sorry pass the ref where? – Aly Nov 14 '12 at 16:29
  • @Aly presumably you are passing the functors somewhere where they are getting copied, hence the problem. So pass the std::ref instead. – juanchopanza Nov 14 '12 at 16:32