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.
Related
I'm looking for a clean STL way to use an existing C buffer (char* and size_t) as a string stream. I would prefer to use STL classes as a basis because it has built-in safeguards and error handling.
note: I cannot use additional libraries (otherwise I would use QTextStream)
You can try with std::stringbuf::pubsetbuf. It calls setbuf, but it's implementation defined whether that will have any effect. If it does, it'll replace the underlying string buffer with the char array, without copying all the contents like it normaly does. Worth a try, IMO.
Test it with this code:
std::istringstream strm;
char arr[] = "1234567890";
strm.rdbuf()->pubsetbuf(arr, sizeof(arr));
int i;
strm >> i;
std::cout << i;
Live demo.
I am trying to convert pid types to a const char pointer so that I can pass them in as an argument in a execlp function.
eg. execlp("/bin/ps", "-f", "--ppid", "9340,9345,9346,9342");
I know that you can convert a pid to a string eg. const std::string my_pid(str_pid.str());
And a string to a const char pointer eg. my_pid.c_str();
But how would you concatenate multiple pids into a const char pointer so I can run the execlp command with them?
ostringstream is probably what you want.
For instance,
std::ostringstream ostr;
for (int i=0; i<pids.count(); i++)
{
if (i > 0) ostr << ',';
ostr << pids[i];
}
execlp("/bin/ps", "-f", "--ppid", ostr.str().c_str());
You can concatenate all of your values together into a single std::string first, the pass the final std::string value to execlp(), eg:
std::string pids;
for (however many pids you have)
{
if (!pids.empty())
pids += ",";
pids += std::string(str_pid.str());
}
execlp("/bin/ps", "-f", "--ppid", pids.c_str());
A stringstream would be a good C++ way to do it.
std::stringstream myStream;
myStream << "a c string" << aStringObject << std::endl; // operate on the stream
std::string myNewString = myStream.str(); // create a string object
Treating the data as a stream is a fairly generic way to allow you to serialize and deserialize custom or builtin types. Custom types could include operator<< and operator>> to allow insertion and extraction respectively.
This approach also should have the advantage of speed over using temporary string objects and manipulating them. The stingstream (or any of its base classes) will employ a buffer under the covers. A loop with temporary strings will invoke several more constructors/allocations/destructors each iteration. This does depend on the underlying string representation as well. A copy on write (COW) string implementation would have fewer allocations and may only update a reference, but updating the work string will still require a new string.
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'm trying create simple application in C++. This application has to read from file and displays data. I've written function:
std::vector <AndroidApplication> AndroidApplication::getAllApp(){
std::vector<AndroidApplication> allApp;
std::fstream f;
f.open("freeApps.txt");
std::string line;
if(f.is_open()){
while(getline(f, line)) {
std::string myLine = "";
char * line2 = line.c_str();
myLine = strtok(line2,"\t");
AndroidApplication * tmpApp = new AndroidApplication(myLine[1], myLine[2], myLine[4]);
tmpApp->Developer = myLine[0];
tmpApp->Pop = myLine[3];
tmpApp->Type = myLine[5];
allApp->pushBack(tmpApp);
}
}
return allApp;
}
It throws me an error in line:
myLine = strtok(line2,"\t");
An error:
cannot convert from 'const char *' to 'char *'
Could you tell me how can I deal with it?
Don't use strtok. std::string has its own functions for string-scanning, e.g., find.
To use strtok, you'll need a writeable copy of the string. c_str() returns a read-only pointer.
You can't just "convert it" and forget about it. The pointer you get from .c_str() is to a read-only buffer. You need to copy it into a new buffer to work with: ideally, by avoiding using antiquated functions like strtok in the first place.
(I'm not quite sure what you're doing with that tokenisation, actually; you're just indexing into characters in the once-tokenised string, not indexing tokens.)
You're also confusing dynamic and automatic storage.
std::vector<AndroidApplication> AndroidApplication::getAllApp()
{
std::vector<AndroidApplication> allApp;
// Your use of fstreams can be simplified
std::fstream f("freeApps.txt");
if (!f.is_open())
return allApp;
std::string line;
while (getline(f, line)) {
// This is how you tokenise a string in C++
std::istringstream split(line);
std::vector<std::string> tokens;
for (std::string each;
std::getline(split, each, '\t');
tokens.push_back(each));
// No need for dynamic allocation here,
// and I'm assuming you wanted tokens ("words"), not characters.
AndroidApplication tmpApp(tokens[1], tokens[2], tokens[4]);
tmpApp.Developer = tokens[0];
tmpApp.Pop = tokens[3];
tmpApp.Type = tokens[5];
// The vector contains objects, not pointers
allApp.push_back(tmpApp);
}
return allApp;
}
I suspect the error is actually on the previous line,
char * line2 = line.c_str();
This is because c_str() gives a read-only pointer to the string contents. There is no standard way to get a modifiable C-style string from a C++ string.
The easiest option to read space-separated words from a string (assuming that's what you're tying to do) is to use a string stream:
std::vector<std::string> words;
std::istringstream stream(line);
std::copy(std::istream_iterator<std::string>(stream),
std::istream_iterator<std::string>(),
back_inserter(words));
If you really want to use strtok, then you'll need a writable copy of the string, with a C-style terminator; one way to do this is to copy it into a vector:
std::vector<char> writable(line.c_str(), line.c_str() + line.length() + 1);
std::vector<char *> words;
while (char * word = strtok(words.empty() ? &writable[0] : NULL, " ")) {
words.push_back(word);
}
Bear in mind that strtok is quite difficult to use correctly; you need to call it once for each token, not once to create an array of tokens, and make sure nothing else (such as another thread) calls it until you've finished with the string. I'm not sure that my code is entirely correct; I haven't tried to use this particular form of evil in a long time.
Since you asked for it:
Theoretically you could use const_cast<char*>(line.c_str()) to get a char*. However giving the result of this to strtok (which modifies its parameter) is IIRC not valid c++ (you may cast away constness, but you may not modify a const object). So it might work for your specific platform/compiler or not (and even if it works it might break anytime).
The other way is to create a copy, which is filled with the contents of the string (and modifyable):
std::vector<char> tmp_str(line.begin(), line.end());
myLine = strtok(&tmp_str[0],"\t");
Of course as the other answers tell you in great detail, you really should avoid using functions like strtok in c++ in favour of functionality working directly on std::string (at least unless you have a firm grasp on c++, high performance requirements and know that using the c-api function is faster in your specific case (through profiling)).
I'd like to clear out and reuse an ostringstream (and the underlying buffer) so that my app doesn't have to do as many allocations. How do I reset the object to its initial state?
I've used a sequence of clear and str in the past:
// clear, because eof or other bits may be still set.
s.clear();
s.str("");
Which has done the thing for both input and output stringstreams. Alternatively, you can manually clear, then seek the appropriate sequence to the begin:
s.clear();
s.seekp(0); // for outputs: seek put ptr to start
s.seekg(0); // for inputs: seek get ptr to start
That will prevent some reallocations done by str by overwriting whatever is in the output buffer currently instead. Results are like this:
std::ostringstream s;
s << "hello";
s.seekp(0);
s << "b";
assert(s.str() == "bello");
If you want to use the string for c-functions, you can use std::ends, putting a terminating null like this:
std::ostringstream s;
s << "hello";
s.seekp(0);
s << "b" << std::ends;
assert(s.str().size() == 5 && std::strlen(s.str().data()) == 1);
std::ends is a relict of the deprecated std::strstream, which was able to write directly to a char array you allocated on the stack. You had to insert a terminating null manually. However, std::ends is not deprecated, i think because it's still useful as in the above cases.
Seems to be that the ostr.str("") call does the trick.
If you're going to clear the buffer in a way that will cause it to be cleared before it's first use, you'll need to add something to the buffer first w/ MSVC.
struct Foo {
std::ostringstream d_str;
Foo() {
d_str << std::ends; // Add this
}
void StrFunc(const char *);
template<class T>
inline void StrIt(const T &value) {
d_str.clear();
d_str.seekp(0); // Or else you'll get an error with this seek
d_str << value << std::ends;
StrFunc(d_str.str().c_str()); // And your string will be empty
}
};
You don't. Use two differently named streams for clarity and let the optimizing compiler figure out that it can reuse the old one.