I saw this users post yesterday. And I thought that was a cool way to output a vector. So I typed up an example and asked myself how does this compare to a for each
loop?
template <typename T>
void printVectorO(std::vector<T> &v)
{
std::cout << "Ostream_iterator contents: " << std::endl;
auto start = std::chrono::high_resolution_clock::now();
std::ostream_iterator<T> ost(std::cout, " ");
std::copy(begin(v), end(v), ost);
std::cout << std::endl;
auto end = std::chrono::high_resolution_clock::now();
auto time = end - start;
auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(time);
std::cout << "Ostream_iterator computation took: " << nano.count() << " nano seconds"<< std::endl;
std::cout << std::endl;
}
template <typename T>
void printVectorC(std::vector<T> &v)
{
std::cout << "For Each Loop contents: " << std::endl;
auto start = std::chrono::high_resolution_clock::now();
for (auto && e : v) std::cout << e << " ";
std::cout << std::endl;
auto end = std::chrono::high_resolution_clock::now();
auto time = end - start;
auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(time);
std::cout << "For Each Loop took: " << nano.count() << " nano seconds" << std::endl;
std::cout << std::endl;
}
I used 3 vectors to test this:
std::vector<double> doubles = { 3.15, 2.17, 2.555, 2.014 };
std::vector<std::string> strings = { "Hi", "how", "are", "you" };
std::vector<int> ints = { 3, 2 , 2 , 2 };
And I get various results. The for each
loop always beats the ostream_iterator
when I output the doubles (ex 41856 vs 11207 and 55198 vs 10308 nanoseconds). Sometimes the string ostream_iterator
beats out the for each
loop, and the for each
loop and ostream_iterator
almost stay neck and neck with integers.
Why is this? What is going on behind the scenes of ostream_iterator
? When would I use ostream_iterator
over a for each
loop when it comes to efficiency and speed?
Beware of micro-benchmarks.
I have several general comments regarding this code:
Here is the corrected benchmark:
constexpr unsigned ITERATIONS = 1000000;
template <typename T>
void printVectorO(const std::vector<T> &v)
{
std::cout << "Ostream_iterator contents\n";
auto start = std::chrono::high_resolution_clock::now();
for (unsigned i=0 ; i < ITERATIONS; ++i) {
std::ostream_iterator<T> ost(std::cout, " ");
std::copy(begin(v), end(v), ost);
std::cout << '\n';
}
auto end = std::chrono::high_resolution_clock::now();
auto time = end - start;
auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(time);
std::cout << "Ostream_iterator computation took: "
<< nano.count() / ITERATIONS << " nano seconds\n\n";
}
template <typename T>
void printVectorC(const std::vector<T> &v)
{
std::cout << "For Each Loop contents\n";
auto start = std::chrono::high_resolution_clock::now();
for (unsigned i=0 ; i < ITERATIONS ; ++i) {
for (auto && e : v) std::cout << e << " ";
std::cout << '\n';
}
auto end = std::chrono::high_resolution_clock::now();
auto time = end - start;
auto nano = std::chrono::duration_cast<std::chrono::nanoseconds>(time);
std::cout << "For Each Loop took: "
<< nano.count() / ITERATIONS << " nano seconds\n\n";
}
And invoking it with:
template <class Container>
void test(const Container & ctr)
{
printVectorC2(ctr);
printVectorO2(ctr);
}
int main()
{
std::vector<double> doubles = { 3.15, 2.17, 2.555, 2.014 };
test(doubles);
std::vector<std::string> strings = { "Hi", "how", "are", "you" };
test(strings);
std::vector<int> ints = { 3, 2 , 2 , 2 };
test(ints);
}
And now, after grepping for nano we have:
For Each Loop took: 2045 nano seconds
Ostream_iterator computation took: 2033 nano seconds
For Each Loop took: 487 nano seconds
Ostream_iterator computation took: 485 nano seconds
For Each Loop took: 503 nano seconds
Ostream_iterator computation took: 499 nano seconds
There is barely any difference. Actually, with this specific run it seems that the ostream version is faster. But running it again gives slightly different results.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With