NeverMore
NeverMore

Reputation: 51

The right way to write a vector to a binary file by iterator in C++

I have searched a lot for this type of questions but got no satisfied answers.

I am working on a function to write a vector container to a binary file using ofstream::write method in C++.

#include <vector>
#include <fstream>

typedef std::vector<unsigned char> byteArray;

byteArray data;
data.push_back('a');
data.push_back('b');
data.push_back('c');
data.push_back('d');

std::ofstream fout("out_file", std::ios::out | std::ios::trunc | std::ios::binary);

// I know the right way should be as following:
fout.write((char *)&data[0], data.size());

// But what I cannot understand is why the following expression is wrong, since gcc compiler says
// invalid cast from type ‘__gnu_cxx::__normal_iterator<unsigned char*, std::vector<unsigned char> >’ to type ‘char*’

for(auto iter = data.begin(); iter != data.end(); iter++)
{
    fout.write((char *)iter, 1);
}

fout.close();

As I understand, iterator iter is a pointer which points to one element in vector 'data'. So I think that (char *) iter would re-interpret the underlying data type as char, then it should satisfy the parameter requirement of fout.write. But actually, this is not the case. I am also very confused that gcc says iter is a type of iterator<unsigned char*, std::vector >, right? Should the iter not be unsigned char * type?

what do I get wrong? Thanks a lot for any help.

Upvotes: 0

Views: 417

Answers (2)

Olaf Dietsche
Olaf Dietsche

Reputation: 74078

A pointer may be used as an iterator, but an iterator need not be a pointer.

An iterator behaves more or less like a pointer by providing operations for dereferencing operator*(), incrementing operator++(), etc., see requirements of e.g. LegacyInputIterator

Although the concrete definitions change over time, see std::input_or_output_iterator for definitions in C++20.

Upvotes: 1

Drew Dormann
Drew Dormann

Reputation: 63912

As I understand, iterator iter is a pointer

It is not. std::vector::iterator is an unspecified type.

You can expect it to have some pointer-like properties, but you should make no assumptions about what specific type it may be.

Since you need a pointer, dereference the iterator and take the address of that result. That's a pointer.

fout.write((char *)&*iter, 1);

Better still, use C++ casts instead of the hard-to-track C casts.

fout.write( static_cast<char*>(&*iter), 1 );

Even safer (Martin York is always a precious gem) -- don't assume the size of the contained type. It could change in the future. This change adds no overhedd.

fout.write( static_cast<char*>(&*iter), size_of(byteArray[0]) );

Upvotes: 2

Related Questions