Jump to content
  • Advertisement
Sign in to follow this  
ZQJ

auto_array_ptr/reading into a vector

This topic is 4860 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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).

Share this post


Link to post
Share on other sites
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>());

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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 :)

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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);

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!