Search code examples
c++11iteratorostream

When to use ostream_iterator


As I know, we can use ostream_iterator in c++11 to print a container.
For example,

std::vector<int> myvector;
for (int i=1; i<10; ++i) myvector.push_back(i*10);

std::copy ( myvector.begin(), myvector.end(), std::ostream_iterator<int>{std::cout, " "} );

I don't know when and why we use the code above, instead of traditional way, such as:

for(const auto & i : myvector) std::cout<<i<<" ";

In my opinion, the traditional way is faster because there is no copy, am I right?


Solution

  • std::ostream_iterator is a single-pass OutputIterator, so it can be used in any algorithms which accept such iterator. The use of it for outputing vector of int-s is just for presenting its capabilities.

    In my opinion, the traditional way is faster because there is no copy, am I right?

    You may find here: http://en.cppreference.com/w/cpp/algorithm/copy that copy is implemented quite similarly to your for-auto loop. It is also specialized for various types to work as efficient as possible. On the other hand writing to std::ostream_iterator is done by assignment to it, and you can read here : http://en.cppreference.com/w/cpp/iterator/ostream_iterator/operator%3D that it resolves to *out_stream << value; operation (if delimiter is ignored).

    You may also find that this iterator suffers from the problem of extra trailing delimiter which is inserted at the end. To fix this there will be (possibly in C++17) a new is a single-pass OutputIterator std::experimental::ostream_joiner

    A short (and maybe silly) example where using iterator is usefull. The point is that you can direct your data to any sink - a file, console output, memory buffer. Whatever output you choose, MyData::serialize does not needs changes, you only need to provide OutputIterator.

    struct MyData {
        std::vector<int> data = {1,2,3,4};
    
        template<typename T>
        void serialize(T iterator) {
            std::copy(data.begin(), data.end(), iterator);
        }
    };
    
    int main()
    {
        MyData data;
    
        // Output to stream 
        data.serialize(std::ostream_iterator<int>(std::cout, ","));
    
        // Output to memory
        std::vector<int> copy;
        data.serialize(std::back_inserter(copy));
    
        // Other uses with different iterator adaptors:
        // std::front_insert_iterator
        // other, maybe custom ones
    }