2

I want to populate a istringstream object with content from vector of strings. Is there an elegant way to do this? I am doing the following now, which is not nice:

vector<string> vec = {"apple", "banana", "dog", "cat"};
string one_str;
for (string s: vec) {
    one_str += s + " ";
}
istringstream iss(one_str);

Note that I want to populate istringstream and not stringstream or ostringstream

saha
  • 97
  • 8
  • 1
    What's wrong with this approach? (Except you should use `string& s` to not make copies) – super Feb 25 '18 at 19:49
  • Possible duplicate of [C++: vector to stringstream](https://stackoverflow.com/questions/3008094/c-vector-to-stringstream) – Shashwat Kumar Feb 25 '18 at 20:00
  • @ShashwatKumar: That question concerns one way of satisfying this requirement, but it doesn't preclude a different, more elegant approach. – Davis Herring Feb 26 '18 at 04:25
  • Saha, it depends on what you call "elegant". You could create a stream buffer with the content of the vector and set this buffer to the istringstream object (see ios::rdbuf ( http://www.cplusplus.com/reference/ios/ios/rdbuf/ )). This way you avoid creating a temporary buffer (your one_str..). – Wolfgang Feb 26 '18 at 07:10

1 Answers1

0

You can't make an istringstream read from any external source: it always makes a copy, even of a single string. You can, however, make a stream that reads from any data source by making your own streambuf class and making an istream from a pointer to an instance of it. A minimal version needs only one method overridden:

#include<streambuf>
#include<string>
#include<vector>

struct stringsbuf : std::streambuf {
  stringsbuf(const std::string *b,const std::string *e) : ss(b),se(e) {}
  stringsbuf(const std::vector<std::string> *v) : // pointer vs. temporaries
    ss(&v->front()),se(ss+v->size()) {}

  int_type underflow() override {
    while(ss!=se) {
      auto &s=*ss++;
      if(s.empty()) continue;
      char *p=const_cast<char*>(s.data());
      setg(p,p,p+s.size());
      return *p;
    }
    return traits_type::eof();
  }

private:
  const std::string *ss,*se;   // next string to load, and past-the-end string
};

This could of course be made more efficient and featureful by adding one or more of xsgetn, seekoff, seekpos, and showmanyc. It could also be made generic (not only on character type, but also by accepting any string-valued iterators).

The elegance here lies in the fact that no concatenated string is ever constructed (except perhaps by the client that reads from an istream based on a stringsbuf).

Davis Herring
  • 36,443
  • 4
  • 48
  • 76