1

I have a loop which reads though a file line by line using a while loop and std::getline.

while(file.good())
{
    std::string line;
    std::getline(file, line);
    vec.push_back(line); /* std::vector */
}

Is there a way to use C++ 14, or later standards, to ommit the tempoary storage in line?

I believe the following will work, but requires an ugly extra push_back() call.

while(file.good())
{
    vec.push_back(std::string()); /* std::vector */
    std::getline(file, vec.back());
}

Note I've not actually run this second snippet through a compiler yet, but I'm pretty sure something along these lines is valid. But can the additional push_back line be avoided?

C++ 14, 17 or 20 code would be fine if versions later than C++ 14 allow something to be done.

FreelanceConsultant
  • 13,167
  • 27
  • 115
  • 225

1 Answers1

4

First of all, you generally want to avoid a loop of the form while (file.good()).

If you're going to do this with a loop, you generally want to use the return from getline as your condition:

std::string line;

while (std::getline(file, line)) {
    vec.push_back(line);
}

This tries to read a line, then if (and only if) that succeeds, adds the line to the vector.

Getting to the question you asked though: yes and no, but mostly no.

You have to create a string object, then read the data into that string object. The string object has to exist before you can read data into it.

If you're concerned mostly with making the code look as neat and tidy as possible, you can hide the temporary string object, such as by using a proxy. Using that, you could write your code something like this:

std::vector<std::string> vec{ std::istream_iterator<line>(infile), 
                              std::istream_iterator<line>() };

This hides the temporary string object, but doesn't really eliminate it.

It's also possible you're concerned with the inefficiency of reading the data into one string object, then having to copy that string object into the vector (then destroying the first string object).

If that's your real concern, you probably want to use std::move on the source string to move the strings into the vector instead of copying them. Instead of copying the entire content of the string from one place to another, this will normally just copy a pointer to the data, set the originating string to know that it's now empty, and it'll be done--fast and cheap, regardless of how long the string might be.

The exception here is that most modern implementations of std::string have what's called a "short string optimization". This means if the string you're storing is short enough (typically around 15 characters or less), it gets stored in the string object itself instead of being allocated separately, with a pointer to that data in the string object. In this case, moving a string object still involves copying all the data it contains--but pretty much by definition, this is limited to short strings, were copying all the data is fairly inconsquential.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • `push_back(std::move( some_string))` is as good as `emplace_back( std::move(some_string))`, no? Not sure if I miss something – 463035818_is_not_an_ai Aug 04 '21 at 19:03
  • 1
    @463035818_is_not_a_number: Yes, it is, at least as far as the compiler--there's an overload of `vector::push_back` that takes a rvalue reference. I prefer to use `emplace_back` for this case, but it's not strictly necessary. – Jerry Coffin Aug 04 '21 at 19:06
  • Presumably in your second snippet, `line` is a `std::string`, and doesn't mean something else? How does this iterator solution work - does it automatically iterate until it finds an end of line character? – FreelanceConsultant Aug 04 '21 at 19:25
  • @FreelanceConsultant "*Presumably in your second snippet, `line` is a `std::string`*" - no, actually it is a proxy class (you can't use a variable in a template parameter) that overloads `operator>>` to call `std::getline()`. Did you look at [the code linked to](https://stackoverflow.com/questions/1567082/#1567703) in Jerry's answer above? – Remy Lebeau Aug 04 '21 at 19:28
  • If you `emplace_back` the temporary string it will move it instead of copying. – Camwin Aug 04 '21 at 20:14