auto_array_ptr/reading into a vector

Started by
8 comments, last by Brother Bob 18 years, 4 months ago
Why isn't there an auto_array_ptr in C++? Or, to put the question another way, how do I read binary data from a file into a vector? The reason these two questions seem related to me is because I've been writing a simple ZIP file reader (I'm basically a C programmer), and if I want to read binary data into a dynamic array I seem to have 3 choices: use C pointers and have an exception-safety nightmare, write my own auto_array_ptr or something like this: std::vector<char> data(size); input_stream.read(&data[0], size); Which I don't like for two reasons: first, I don't believe &data[0] is guaranteed to work on all implementations and second I think the std::vector constructor will initialize the array which is a waste of time. However, auto_array_ptr also isn't in boost which leads me to think that there is a really good way to do this or a really good reason why the boost people haven't put it in (I think it has been proposed).
Advertisement
Because there's std::vector, which is guaranteed to have continguous memory.

std::ifstream input_stream("filename", std::ios_base::binary);std::vector<char> data((std::istreambuf_iterator<char>(input_stream)),                        std::istreambuf_iterator<char>());
Quote:Original post by ZQJ
Which I don't like for two reasons: first, I don't believe &data[0] is guaranteed to work on all implementations

As long as the vector is not empty, yes it is guaranteed to work on all standards conforming implementations.
Quote:and second I think the std::vector constructor will initialize the array which is a waste of time.

Let me get this straight. You're worried about the cost of default-initialising a vector when you're about to read into it from a file? You do realise that file I/O is orders of magnitude slower than memory access, right? That default initialisation is going to be something like 0.1% of the total time spent in that section of code. Don't worry about it.

Enigma
Quote:Original post by SiCrane
Because there's std::vector, which is guaranteed to have continguous memory.

std::ifstream input_stream("filename", std::ios_base::binary);std::vector<char> data((std::istreambuf_iterator<char>(input_stream)),                        std::istreambuf_iterator<char>());


Thanks, but how do I read a set number of bytes into memory that way? (Ok, I could do the other way of course).

Quote:Original post by Enigma
Let me get this straight. You're worried about the cost of default-initialising a vector when you're about to read into it from a file? You do realise that file I/O is orders of magnitude slower than memory access, right? That default initialisation is going to be something like 0.1% of the total time spent in that section of code. Don't worry about it.


True, I just hate wasted program time in general :)
Quote:Original post by ZQJ
Quote:Original post by SiCrane
Because there's std::vector, which is guaranteed to have continguous memory.

std::ifstream input_stream("filename", std::ios_base::binary);std::vector<char> data((std::istreambuf_iterator<char>(input_stream)),                        std::istreambuf_iterator<char>());


Thanks, but how do I read a set number of bytes into memory that way? (Ok, I could do the other way of course).


One of many ways:

template < typename value_t >class istreambuf_generator {    typedef value_t value_type;    typedef std::istreambuf_iterator< value_type > iterator_type;    typedef std::istream istream_type;    iterator_type i;public:    istreambuf_generator( istream_type & istream )        : i( istream )    {    }    value_type operator()( void ) {        assert( i != iterator_type() && "Tried to read past EOF" );        value_type value = *i;        ++i;        return value;    }};std::ifstream input_stream("filename", std::ios_base::binary);std::size_t size = ...;std::vector< char > data( size );std::generate( data.begin() , data.end() , istreambuf_generator< char >( input_stream ) );


Quote:
Quote:Original post by Enigma
Let me get this straight. You're worried about the cost of default-initialising a vector when you're about to read into it from a file? You do realise that file I/O is orders of magnitude slower than memory access, right? That default initialisation is going to be something like 0.1% of the total time spent in that section of code. Don't worry about it.


True, I just hate wasted program time in general :)


Of course, by worrying about trivial things like this, you waste your time, which in turn means you're unable to spend that time optimizing someplace it'll count - the end result being more wasted program time total than if you had properly allocated your time.

If you're using Boost, there's also boost::scoped_array, which would be just like a theoretical std::auto_array[_ptr] minus the "Assignment-that-really-steals-ownership" and "Release" semantics.
Quote:Original post by SiCrane
std::vector<char> data((std::istreambuf_iterator<char>(input_stream)),                        std::istreambuf_iterator<char>());


Why is the extra set of parentheses around the first constructor argument necessary? Without it, VC++ sees the line as a function prototype, rather than a variable declaration, but why does the extra set of brackets fix this?

Quote:Original post by bakery2k1
Quote:Original post by SiCrane
std::vector<char> data((std::istreambuf_iterator<char>(input_stream)),                        std::istreambuf_iterator<char>());


Why is the extra set of parentheses around the first constructor argument necessary? Without it, VC++ sees the line as a function prototype, rather than a variable declaration, but why does the extra set of brackets fix this?

You are very correct about the line being a function prototype without the parentheses. It has to do with the "rule", if it looks like a function prototype, it is a function prototype. However, parentheses around the parameter type and name in a function declaration is illegal, so the only way to intepret that line would be a variable definition which passes values to the constructor.
Excellent, thanks!
Quote:Original post by Brother Bob
Quote:Original post by bakery2k1
Quote:Original post by SiCrane
std::vector<char> data((std::istreambuf_iterator<char>(input_stream)),                        std::istreambuf_iterator<char>());


Why is the extra set of parentheses around the first constructor argument necessary? Without it, VC++ sees the line as a function prototype, rather than a variable declaration, but why does the extra set of brackets fix this?

You are very correct about the line being a function prototype without the parentheses. It has to do with the "rule", if it looks like a function prototype, it is a function prototype. However, parentheses around the parameter type and name in a function declaration is illegal, so the only way to intepret that line would be a variable definition which passes values to the constructor.


That's all true and all, but it's totally opaque unless you've gotten bitten by it before.

As I recall, the Exceptional C++ article about it suggests the following instead:
std::istreambuf_iterator<char> b(input_stream), e;std::vector<char> data(b,e);
Quote:Original post by me22
That's all true and all, but it's totally opaque unless you've gotten bitten by it before.

As I recall, the Exceptional C++ article about it suggests the following instead:
std::istreambuf_iterator<char> b(input_stream), e;std::vector<char> data(b,e);

I have made the mistake of making the function instead of the object quite a few times, and personally I think the cleanest solution is what SiCrane posted. Scott Meyers also suggests your appoach in Effective STL, but as I understand it mainly due to the fact that some old compilers just can't handle SiCrane's version, so it will be more portable.

This topic is closed to new replies.

Advertisement