In C++, whenever a function creates many (hundreds or thousands of) values, I used to have the caller pass an array that my function then fills with the output values:
My question is: Is the insert_iterator the right or standard way to do it?
Yes. Otherwise, if you are not going to have at least as many elements in your container as there will be computed values. This is not always possible, specially, if you want to write to a stream. So, you are good.
If you ever have a group of objects, chances are you have at least a few methods that work on that group of objects (otherwise, what are you doing with them?)
If that's the case, it would make sense to have those methods in a class that contain both said objects and methods.
If that makes sense and you have such a class, return it.
I virtually never find myself thinking that I wish I could return more than one value. By the fact that a method should only do one small thing, your parameters and return values tend to have a relationship, and so are more often than not deserving of a class that contains them, so returning more than one value is rarely interesting (Maybe I wished for it 5 times in 20 years--each time I refactored instead, came up with a better result and realized my first attempt was sub-standard.)
Response to Edit: Well, if you need to return hundreds and thousands if values, a tuple of course would not be the way to go. Best pick the solution with the iterator then, but it's best not use any specific iterator type.
If you use iterators, you should use them as generic as possible. In your function you have used an insert iterator like insert_iterator< vector<int> >
. You lost any genericity. Do it like this:
template<typename OutputIterator>
void computeValues(int input, OutputIterator output) {
...
}
Whatever you give it, it will work now. But it will not work if you have different types in the return set. You can use a tuple then. Also available as std::tuple
in the next C++ Standard:
boost::tuple<int, bool, char> computeValues(int input) {
....
}
If the amount of values is variadic and the type of the values is from a fixed set, like (int, bool, char), you can look into a container of boost::variant
. This however implies changes only on the call-side. You can keep the iterator style of above:
std::vector< boost::variant<int, bool, char> > data;
computeValues(42, std::back_inserter(data));
You could return a smart pointer to a vector. That should work and no copy of the vector will be made.
If you don't want to keep the smart pointer for the rest of your program, you could simply create a vector before calling the function, and swap both vectors.
Your example with insert_iterator won't work, because insert_iterator is a template requiring a container for a parameter. You could declare it
void computeValues(int input, std::insert_iterator<vector<int> > outputInserter);
or
template<class Container>
void computeValues(int input, std::insert_iterator<Container> outputInserter);
The first will tie you back to a vector<int> implementation, without any obvious advantages over your initial code. The second is less restrictive, but implementing as a template will give you other constraints that might make it a less desirable choice.
Actually, your old method of passing in the vector has a lot to recommend it -- it's efficient, reliable, and easy to understand. The disadvantages are real but don't apply equally in all cases. Are people really going to want the data in an std::set or list? Are they really going to want to use the long list of numbers without bothering to assign it to a variable first (one of the reasons to return something via 'return' rather than a parameter)? Being generic is nice, but there is a cost in your programming time that may not be redeemed.