I'd much rather just see this as a tuple of doubles (or array thereof); it removes all the guesswork that a tuple of pointers to doubles has created.
Instead of thinking of this as a potential leak, think of it in terms of ownership. When you declare a local variable of type double
, the stack owns it and it will be cleaned up. When you create one of type double*
, the stack owns the pointer but does not own the value, so the value may not be cleaned up. Clearly just declaring a double
is simpler and easier, so when that's an option, prefer it.
Now consider other potential owners. A tuple containing POD types such as std::tuple<double, double>
would own and then clean up the doubles, but a tuple containing a pointer type isn't clear. Cleaning up a std::tuple<double*, double*>
won't clean up the doubles. Clearly just using a tuple of doubles is simpler and easier, so if that's an option, prefer it.
But, I'm assuming for various reasons you have to use a tuple of pointers to doubles.
Consider then what lifetime you need for your underlying data. How can you get this lifetime? Can you give ownership of the doubles to something else that will get cleaned up at the right time, and store their addresses in the tuple's non-owning pointers to doubles? For instance have your lambda capture an external container by reference, and put your doubles in it, and store just their addresses in the tuples.
Here's an attempt to show what I mean...but be wary doing this with the vector as I show it. I know nothing of hpx::parallel::reduce
, but I assume that its parallel nature will render this simplified version completely unsafe. Two interleaved calls to push_back
and back
will result in incorrect tuples being created; two overlapping calls to push_back
could easily corrupt the vector. A more complex version could synchronize its use of the container.
std::vector<double> v; // XXX: probably unsafe for parallel reduce
boost::tuple<double*,double*> res = hpx::parallel::reduce(hpx::parallel::par,
iter, iter+4,
boost::make_tuple<double*,double*>(g,h), [&v](reference a, reference b) {
v.push_back(*boost::get<1>(b) * *boost::get<0>(b));
return boost::make_tuple<double*,double*>(&v.back(), &v.back()); });