0

I have:

  • vector of unique_ptrs of ObjectA

  • vector of newly default constructed vector of ObjectB, and

  • a function in Object B that has signature void f(unique_ptr<ObjectA> o).

(word Object omitted from here on)

How do I do Bvec[i].f(Avec[i]) for all 0 < i < length in parallel?

I have tried using transform(Bvec.begin(), Bvec.end(), A.begin(), B.begin(), mem_fun_ref(&B::f)), but it gives a bunch of errors and I'm not sure if it would even pass the right A as parameter, let alone allow me to move them. (&B::f(A.begin()) would not work as the last parameter either.

I have also thought of using for_each and then a lambda function, but not sure how to get the corresponding element. I thought of incrementing a counter, but then I don't think that parallelizes well (I could be wrong).

I can, of course, use a for loop from 0 to end, but I am pretty sure there is a simple thing I'm missing, and it is not parallel with a simple for loop.

Thanks.

chemelnucfin
  • 411
  • 1
  • 4
  • 9
  • You realize that, by passing a unique pointer, you are *transferring ownership* of those pointers out of the list and into that function, correct? Also, it's not in parallel with `std::transform` either. – Nicol Bolas Dec 07 '11 at 22:02
  • @NicolBolas Yes, I do with the transferring, but no I did not know that transform was not done in parallel.. thanks. (MTG player? off topic, nm) – chemelnucfin Dec 07 '11 at 22:04
  • Do you mean concurrently when you say parallely? `transform` will work ,as every other stdlib algorithm, sequentially. Also, `transform` wont ever work, as it requires a functor that returns something. – pmr Dec 07 '11 at 22:21
  • @pmr yes, I guess concurrently. I can see 2 rows of boxes in my head with an arrow pointing from one row to another which should easily be done at the same time right? – chemelnucfin Dec 07 '11 at 22:28
  • No, and it will not necessarily be faster than doing it in order. This entirely depends on the amount of work done in `f`. – pmr Dec 07 '11 at 22:38
  • How is it supposed to be done in parallel? Do you have some concurrency framework in mind? C++/AMP or so? – Kerrek SB Dec 07 '11 at 22:42
  • @KerrekSB I was just thinking some library function (or the like) that would just automatically call f in parallel on each element. similar to the parallel form of for_each. – chemelnucfin Dec 07 '11 at 22:55
  • @pmr I'm guessing it would be ideally linearly faster, as I do have other functions using object B in the same loop, which then recursively calls this loop function after the transform (I'm building trees if that helps). – chemelnucfin Dec 07 '11 at 22:59
  • @chemelnucfin There is no standard parallel form of `for_each`. You must be using some framework or library. – pmr Dec 07 '11 at 23:03

1 Answers1

0

Here is a non-parallel implementation using a handmade algorithm. I'm sure someone more versed in the functional could come up with a more elegant solution. The problem with transform is, that we cannot use it with functions that return void and I can't remember another stdlib function that takes two ranges and apply them to each other. If you really want to parallelize this, it needs to be done in the apply_to function. Launching an async task (e.g. std::async(*begin++, *begin2++) could work, although I have no experience with this and cannot get it to work on gcc 4.6.2.

#include <iterator>
#include <memory>
#include <vector>
#include <algorithm>
#include <functional>


// this is very naive it should check call different versions
// depending on the value_type of iterator2, especially considering
// that a tuple would make sense
template<typename InputIterator1, typename InputIterator2>
void apply_to(InputIterator1 begin, InputIterator1 end, InputIterator2 begin2) {
  while(begin != end) {
    (*begin++)(*begin2++);
  }
}

struct Foo {

};

struct Bar {
  void f(std::unique_ptr<Foo>) { }
};


int main()
{
  std::vector< std::unique_ptr<Foo> > foos(10);
  std::vector< Bar > bars(10);
  std::vector< std::function<void(std::unique_ptr<Foo>) > > funs;

  std::transform(bars.begin(), bars.end(), std::back_inserter(funs),
                 // non-const due to f non-const, change accordingly
                 [](Bar& b) { return std::bind(&Bar::f, &b, std::placeholders::_1); });

  // now we just need to apply each element in foos with funs
  apply_to(funs.begin(), funs.end(), std::make_move_iterator(foos.begin()));


  return 0;
}
pmr
  • 58,701
  • 10
  • 113
  • 156