TimD1
TimD1

Reputation: 1032

C++ initializing vector with iterators

I am attempting to read a file of unsigned characters into a vector. My slightly roundabout way of doing this is by creating an input file stream, reading that data into a stringstream, and initializing a vector using the contents of the stringstream. There is probably a much better way to do this, and my existing code causes a segmentation fault using certain files.

string file_name = "output/comp" + to_string(start_id) + ".xml";

if( !file_exists(file_name))
{
    cout << "File could not be found." << endl;
    return 0;
}

ifstream ifs(file_name);
stringstream ss;
ss << ifs.rdbuf();
ss >> noskipws;

vector<unsigned char> raw_data(ss.str().begin(), ss.str().end());

I have included all the necessary headers and using declarations, and file_exists() returns a boolean value indicating whether or not the file exists.

My question is this: Why is the above code incorrect, and what is the best method for correctly accomplishing the same objective?

Upvotes: 0

Views: 5149

Answers (3)

NathanOliver
NathanOliver

Reputation: 180630

The problem with

vector<unsigned char> raw_data(ss.str().begin(), ss.str().end());

is that str() returns a temporary string. This means the string you use for begin is not the same string you use for end. Since the iterators do not refer to the same string you cannot use them together.

Instead of using a strignstream we can read the file directly into the vector using istream_iterators like

std::ifstream ifs(file_name);
std::istream_iterator<unsigned char> start(ifs), end;
std::vector<unsigned char> raw_data(start, end);

Upvotes: 2

Cornstalks
Cornstalks

Reputation: 38218

std::stringstream::str() returns a std::string. That is, it's a temporary string.

So ss.str().begin() returns the beginning iterator for a temporary string, and ss.str().end() returns the ending iterator of a different temporary string, because both ss.str() calls are returning different temporary strings. You can't mix iterators between different objects!

To fix this, use one string:

std::string str = ss.str();

And now just pass str.begin() and str.end().

Upvotes: 8

kirinthos
kirinthos

Reputation: 452

i'm not exactly sure why that would cause a segfault, perhaps something in string stream, but with c++11 it's very easy to read a file into a string once you have any istream derivative:

std::string readFileAsString(std::istream& stream)
{
     return std::string(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());
}

edit sorry, I forgot you wanted the bytes at the end

return std::vector<char>(std::istreambuf_iterator<char>(stream), std::istreambuf_iterator<char>());

Upvotes: 0

Related Questions