I was trying out the below snippet but it is not giving the desired output:
#include<iostream>
#include<sstream>
using namespace std;
void MyPrint(ostream& stream)
{
cout<<stream.rdbuf()<< endl;
}
int main()
{
stringstream ss;
ss<<"hello there";
MyPrint(ss); //Prints fine
ostringstream oss;
oss<<"hello there";
MyPrint(oss); //Does not print anything
getchar();
}
I am aware that the only possible differences between stringstream and ostringstream is that the later forces the direction and is a bit faster than stringstream.
Am I missing out on anything?
PS: A similar question was posted earlier but didn't get any answers.
std::stringstream and std::ostringstream pass different
flags to the std::stringbuf. In particular, the
std::stringbuf of an std::ostringstream does not support
reading. And std::cout << stream.rdbuf() is a read operation
on the streambuf.
The way to extract characters from an std::ostringstream is by
using the std::ostringstream::str() function.
stringstream shouldn't be thought of as a bidirectional implementation of ostringstream and istringstream. It is implemented as a derrived class of both ostringstream and istringstream, which is why it implements both input and output capabilities.
Choosing which one to use depends on what it is used for. If you only need to write data to it on a stream without being able to access the data via a stream, then an ostringstream is all you would need. However, if you want to implement bidirectional on something you provide to an API but restrict it, you can cast it:
stringstream ss; // My bidirectional stream
ostringstream *p_os = &ss; // Now an output stream to be passed to something only allowed to write to it.
int bytes = collectSomeData(p_oss);
Related
I have a stringstream that I'd like to iterate and determine if a substring exists in it.
I know that I could just convert to a string and do std::string::find(), but I was just hoping to avoid the conversion from stringstream to string if possible.
I understand the following won't work because the istream_iterator uses char as its type (not string)
stringstream ssBody;
string sFindThis;
...
auto itr = std::find (
istreambuf_iterator<char>(ssBody),
istreambuf_iterator<char>(),
sFindThis
);
But can I somehow search for a string in stringstream with std::find or similar without a conversion to string?
The C++ standard does not define any std::[io]?stringstream methods for searching its contents.
Neither can you use std::istreambuf_iterator together with std::search(), since std::istreambuf_iterator is an input iterator, but std::search() requires a forward iterator.
The only effective way to search a string stream is to convert it to a std::string, first.
using pubsetbuf it is possible to associate a buffer with basic_stringbuf member and then search the buffer, however behavior of this function is implementation defined. explanations and the example are from http://en.cppreference.com/w/cpp/io/basic_stringbuf/setbuf
#include <iostream>
#include <sstream>
int main()
{
std::ostringstream ss;
char c[1024] = {};
ss.rdbuf()->pubsetbuf(c, 1024);
ss << 3.14 << '\n';
std::cout << c << '\n';
}
Apparently boost::asio::async_read doesn't like strings, as the only overload of boost::asio::buffer allows me to create const_buffers, so I'm stuck with reading everything into a streambuf.
Now I want to copy the contents of the streambuf into a string, but it apparently only supports writing to char* (sgetn()), creating an istream with the streambuf and using getline().
Is there any other way to create a string with the streambufs contents without excessive copying?
I don't know whether it counts as "excessive copying", but you can use a stringstream:
std::ostringstream ss;
ss << someStreamBuf;
std::string s = ss.str();
Like, to read everything from stdin into a string, do
std::ostringstream ss;
ss << std::cin.rdbuf();
std::string s = ss.str();
Alternatively, you may also use a istreambuf_iterator. You will have to measure whether this or the above way is faster - i don't know.
std::string s((istreambuf_iterator<char>(someStreamBuf)),
istreambuf_iterator<char>());
Note that someStreamBuf above is meant to represent a streambuf*, so take its address as appropriate. Also note the additional parentheses around the first argument in the last example, so that it doesn't interpret it as a function declaration returning a string and taking an iterator and another function pointer ("most vexing parse").
It's really buried in the docs...
Given boost::asio::streambuf b, with size_t buf_size ...
boost::asio::streambuf::const_buffers_type bufs = b.data();
std::string str(boost::asio::buffers_begin(bufs),
boost::asio::buffers_begin(bufs) + buf_size);
Another possibility with boost::asio::streambuf is to use boost::asio::buffer_cast<const char*>() in conjunction with boost::asio::streambuf::data() and boost::asio::streambuf::consume() like this:
const char* header=boost::asio::buffer_cast<const char*>(readbuffer.data());
//Do stuff with header, maybe construct a std::string with std::string(header,header+length)
readbuffer.consume(length);
This won't work with normal streambufs and might be considered dirty, but it seems to be the fastest way of doing it.
For boost::asio::streambuf you may find a solution like this:
boost::asio::streambuf buf;
/*put data into buf*/
std::istream is(&buf);
std::string line;
std::getline(is, line);
Print out the string :
std::cout << line << std::endl;
You may find here: http://www.boost.org/doc/libs/1_49_0/doc/html/boost_asio/reference/async_read_until/overload3.html
One can also obtain the characters from asio::streambuf using std::basic_streambuf::sgetn:
asio::streambuf in;
// ...
char cbuf[in.size()+1]; int rc = in.sgetn (cbuf, sizeof cbuf); cbuf[rc] = 0;
std::string str (cbuf, rc);
The reason you can only create const_buffer from std::string is because std::string explicitly doesn't support direct pointer-based writing in its contract. You could do something evil like resize your string to a certain size, then const_cast the constness from c_str() and treat it like a raw char* buffer, but that's very naughty and will get you in trouble someday.
I use std::vector for my buffers because as long as the vector doesn't resize (or you are careful to deal with resizing), you can do direct pointer writing just fine. If I need some of the data as a std::string, I have to copy it out, but the way I deal with my read buffers, anything that needs to last beyond the read callback needs to be copied out regardless.
I didn't see an existing answer for reading exactly n chars into a std::stringstream, so here is how that can be done:
std::stringstream ss;
boost::asio::streambuf sb;
const auto len = 10;
std::copy_n(boost::asio::buffers_begin(sb.data()), len,
std::ostream_iterator<decltype(ss)::char_type>(ss));
Compiler explorer
A simpler answer would be to convert it in std::string and manipulate it some what like this
std::string buffer_to_string(const boost::asio::streambuf &buffer)
{
using boost::asio::buffers_begin;
auto bufs = buffer.data();
std::string result(buffers_begin(bufs), buffers_begin(bufs) + buffer.size());
return result;
}
Giving a very concise code for the task.
I mostly don't like answers that say "You don't want X, you want Y instead and here's how to do Y" but in this instance I'm pretty sure I know what tstenner wanted.
In Boost 1.66, the dynamic string buffer type was added so async_read can directly resize and write to a string buffer.
I tested the first answer and got a compiler error when compiling using "g++ -std=c++11"
What worked for me was:
#include <string>
#include <boost/asio.hpp>
#include <sstream>
//other code ...
boost::asio::streambuf response;
//more code
std::ostringstream sline;
sline << &response; //need '&' or you a compiler error
std::string line = sline.str();
This compiled and ran.
I think it's more like:
streambuf.commit( number_of_bytes_read );
istream istr( &streambuf );
string s;
istr >> s;
I haven't looked into the basic_streambuf code, but I believe that should be just one copy into the string.
I have a function that uses basic_istream as an argument, and I have a std::string with the data I need to pass it. How do I do that?
You can put the string data into a stream:
std::string x;
std::stringstream ss(x); // put string into stream
function_taking_stream(ss);
A full working example showing how to parse a json string using boost property_tree:
#include <iostream>
#include <string>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>
using boost::property_tree::ptree;
int main ()
{
std::string jsonString ("{ \"my key\": \"my value\" }");
ptree pt;
std::stringstream ss(jsonString);
read_json(ss, pt);
std::cout << pt.get<std::string>("my key") << std::endl;
return 0;
}
I have a function that uses basic_istream as an argument...
So I'm assuming you have a function that accepts a variable of a type specialized from the basic_istream template.
...and I have a std::string with the data I need to pass it.
So I'm assuming you want to feed this data into the istream argument.
How do I do that?
You don't. You can't feed output to an input stream!
I think the OP means he has a basic_istream<E> to read from and wants to read to a std::string, not to a std::basic_string<E>.
You should probably write to the basic_string first then convert that to a std::string. If you want to ensure the conversion is correct you probably want a proper UTF-8 to UTF-16 converter.
If you know you are dealing with only ASCII bytes you can do something like:
std::basic_string<E> strTemp;
is >> strTemp;
std::string str( strTemp.begin(), strTemp.end() );
If you have a basic_ostream<E> you can similarly first construct a basic_string<E> from your std::string and then write that to the stream.
You can "specialise" your template function so that if E happens to be char the conversion is quick. For that purpose you can input the two strings as non-const references and the specialised version could just "swap".
Hello! My problem can be described the following way:
I have some data which actually is an array and could be represented as char* data with some size
I also have some legacy code (function) that takes some abstract std::istream object as a param and uses that stream to retrieve data to operate.
So, my question is the following - what would be the easy way to map my data to some std::istream object so that I can pass it to my function? I thought about creating a std::stringstream object from my data, but that means copying and (as I assume) isn't the best solution.
Any ideas how this could be done so that my std::istream operates on the data directly?
Thank you.
If you're looking at actually creating your own stream, I'd look at the Boost.Iostreams library. It makes it easy to create your own stream objects.
Definitely not the easiest way but just in case someone wanted to understand how std streams work inside, this seems to be a very nice introduction about how you can roll your own:
http://www.mr-edd.co.uk/blog/beginners_guide_streambuf
Use string stream:
#include <sstream>
int main()
{
char[] data = "PLOP PLOP PLOP";
int size = 13; // PS I know this is not the same as strlen(data);
std::stringstream stream(std::string(data, size));
// use stream as an istream;
}
If you want to be real effecient you can muck with the stream buffer directly. I have not tried this and do not have a compiler to test with, but the folowing should work:
#include <sstream>
int main()
{
char[] data = "PLOP PLOP PLOP";
int size = 13; // PS I know this is not the same as strlen(data);
std::stringstream stream;
stream.rdbuf()->pubsetbuf(data, size);
// use stream as an istream;
}
What is the most optimal way to get a string or char* pointer into an istream.
I want to do the following
std::string a = "abc..";
//I know this can be done, not sure if this is most efficient
// and not sure about char* pointers
std::istringstream istr (a);
...
foo (istr);
void foo(std::istream& is) {
}
If you want to construct an istringstream from it, a char* up to the null character, or all the stuff from an std::string:
istringstream str(ptr); // char*
istringstream str(other_str); // std::string
If you talk about wanting a raw pointer into the buffer of an istream, you can't do it. Streams get their data on-demand if they need them either from files, terminals or else, optionally buffering their stuff (well, not exactly right. You can use a strstream, which accepts a raw pointer and reads/writes directly from that. But it's a deprecated class - don't use it. I'm lucky i've never done so). If all you want is something you can use somewhat like a pointer, you can use streambuf iterators. They are not really pointers though, so you can't subtract end from begin and other stuffs:
std::istreambuf_iterator<char> begin(one_istream), end;
while(begin != end)
std::cout << *begin++;
If you talk about getting a string out of what was written into a stringstream, you can use ostringstream::str:
ostringstream o;
o << "This is a number: " << 42;
std::string str = o.str(); // str == "This is a number: 42"
Otherwise, you can only generally read stuff from an istream. You need an ostream, then you can do
stream.write(ptr, N);
stream.write(ptr.c_str(), ptr.c_str() + ptr.size());
to write exactly N characters from the bytes that str points to. You can write it into the stream using << too. It will write everything up to the null character, or everything from an std::string, but will respect formatting flags, like the field width:
stream << ptr; // char*
stream << other_str; // everything from std::string
This will work:
std::istringstream is("abc...");
And since istringstream is a istream, you will be able to use your is object as an istream.