I have a ostringstream variable which contains some data.
I want to get set a char * pointer to the data inside the ostringstream.
If I do the following:
std::ostringstream ofs;
.....
const char *stam = (ofs.str()).c_str();
There is a copy of the content of the string in ofs.
I want to get a pointer to that content without a copy.
Is there a way to do so?
This actually answers the question... took a while but I wanted to do it for the same reasons (efficiency vs portability is fine for my situation):
class mybuf : public std::stringbuf {
public:
// expose the terribly named end/begin pointers
char *eback() {
return std::streambuf::eback();
}
char *pptr() {
return std::streambuf::pptr();
}
};
class myos : public std::ostringstream {
mybuf d_buf;
public:
myos() {
// replace buffer
std::basic_ostream<char>::rdbuf(&d_buf);
}
char *ptr();
};
char *myos::ptr() {
// assert contiguous
assert ( tellp() == (d_buf.pptr()-d_buf.eback()) );
return d_buf.eback();
}
int main() {
myos os;
os << "hello";
std::cout << "size: " << os.tellp() << std::endl;
std::string dat(os.ptr(),os.tellp());
std::cout << "data: " << dat << std::endl;
}
This points to, yet again, the deeper, underlying problem with the standard library - a confusion between contracts and "safety". When writing a messaging service, I need a library with efficient contracts... not safety. Other times, when writing a UI, I want strong safety - and cares less about efficiency.
Although you can't get a pointer to the character buffer in the ostringstream, you can get access to its characters without copying them if you switch to using stringstream. A stringstream allows input and output (reading from and writing to the stream), whereas ostringstream allows only output (writing to the stream). Example:
std::stringstream ss;
ss << "This is a test.";
// Read stringstream from index 0. Use different values to look at any character index.
ss.seekg(0);
char ch;
while (ss.get(ch)) { // loop getting single characters
std::cout << ch;
}
ss.clear(); // Clear eof bit in case you want to read more from ss
This site has a pretty good overview of stringstreams and what you can do with them.
Related
I am working in a section of code with very high performance requirements. I need to perform some formatted string operations, but I am trying to avoid memory allocations, even internal library ones.
In the past, I would have done something similar to the following (assuming C++11):
constexpr int BUFFER_SIZE = 200;
char buffer[BUFFER_SIZE];
int index = 0;
index += snprintf(&buffer[index], BUFFER_SIZE-index, "Part A: %d\n", intA);
index += snprintf(&buffer[index], BUFFER_SIZE-index, "Part B: %d\n", intB);
// etc.
I would prefer to use all C++ methods, such as ostringstream, to do this instead of the old C functions.
I realize I could use std::string::reserve and std::ostringstream to procure space ahead of time, but that will still perform at least one allocation.
Does anyone have any suggestions?
Thanks ahead of time.
Does anyone have any suggestions?
Yes, use std::ostrstream. I know it is deprecated. But I find it useful for output to static buffers. No possibility of memory leaks if an exception occurs.
No allocation of memory at all.
#include <strstream> // for std::ostrstream
#include <ostream> // for std::ends
// :
constexpr int BUFFER_SIZE = 200;
char buffer[BUFFER_SIZE];
std::ostrstream osout(buffer, sizeof(buffer));
osout << "Part A: " << intA << "Part B: " << intB << std::ends;
My thanks to all that posted suggestions (even in the comments).
I appreciate the suggestion by SJHowe, being the briefest solution to the problem, but one of the things I am looking to do with this attempt is to start coding for the C++ of the future, and not use anything deprecated.
The solution I decided to go with stems from the comment by Remy Lebeau:
#include <iostream> // For std::ostream and std::streambuf
#include <cstring> // For std::memset
template <int bufferSize>
class FixedBuffer : public std::streambuf
{
public:
FixedBuffer()
: std::streambuf()
{
std::memset(buffer, 0, sizeof(buffer));
setp(buffer, &buffer[bufferSize-1]); // Remember the -1 to preserve the terminator.
setg(buffer, buffer, &buffer[bufferSize-1]); // Technically not necessary for an std::ostream.
}
std::string get() const
{
return buffer;
}
private:
char buffer[bufferSize];
};
//...
constexpr int BUFFER_SIZE = 200;
FixedBuffer<BUFFER_SIZE> buffer;
std::ostream ostr(&buffer);
ostr << "PartA: " << intA << std::endl << "PartB: " << intB << std::endl << std::ends;
I have been using mostly C so I am pretty new into c++. I want to convert a int vector (std::vector) into hexadecimal representation and then store that into a string. I found something I would use in C in the following thread: Converting hex into a string using 'sprintf'
The code proposed by user411313 is the following:
static unsigned char digest[16];
static unsigned char hex_tmp[16];
for (i = 0; i < 16; i++) {
printf("%02x",digest[i]);
sprintf(&hex_tmp[i], "%02x", digest[i]);
}
One of my concerns is that this could go out of index at some point since sprintf may try to add a 0 after the content. Also, I was wondering if there is any way to do it with native C++, perhaps any built function could be used instead of C functions. Is this preferable in c++ over c functions? Thank you very much for your assistance!
if there is any way to do it with native C++, perhaps any built function could be used instead of C functions. Is this preferable in c++ over c functions?
Sure there is a way, and yes it's preferable:
static std::array<unsigned char,16> digest;
static std::string hex_tmp;
for (auto x : digest) {
std::ostringstream oss;
oss << std::hex << std::setw(2) << std::setfill('0') << (unsigned)x;
hex_tmp += oss.str();
}
One of my concerns is that this could go out of index at some point since sprintf may try to add a 0 after the content.
That's a valid concern. The classes used in my code snippet above will overcome all these issues, and you don't need to care about.
You can use std::stringstream
std::string hex_representation(const std::vector<int>& v) {
std::stringstream stream;
for (const auto num : v) {
stream << "0x" << std::hex << std::setw(2) << std::setfill('0') << num
<< ' ';
}
return stream.str();
}
Obviously you can remove the "0x" prefix if you don't need it
Here a live demo.
I have following code snippet to modify the stringstream such that it will have additional one char infront. But, i couldn't get the expected result.
void modifyStream(std::istream& s1)
{
if (s1.putback('Y'))
std::cout << s1.rdbuf() << '\n';
else
std::cout << "putback failed\n";
}
int main(int argc, const char * argv[])
{
const char* str = "Hello, world";
std::stringstream s1(str); // IO stream
modifyStream(s1);
return 0;
}
Output: putback failed
But, i am expecting the output of "YHello, world".
Can someone help to resolve this?
There is a misunderstanding about the putback method in your code: Its purpose is not to prepend data to the stream but to replace one already extracted character with another (you do not add anything, you replace an old character with something new). This is a bit more understandable by reading the documentation of sputbackc which is called by putback.
Example (from encppreference):
std::stringstream s1("Hello, world"); // IO stream
s1.get();
if (s1.putback('Y')) // modifies the buffer
std::cout << s1.rdbuf() << '\n';
else
std::cout << "putback failed\n";
Output:
Yello, world
The call s1.putback('Y') puts the character 'Y' back at the place of the last extracted character (in this case 'H').
in a function, that gets unsigned char && unsigned char length,
void pcap_callback(u_char *args, const struct pcap_pkthdr* pkthdr, const u_char* packet)
{
std::vector<unsigned char> vec(packet, packet+pkthdr->len); // optimized from foo.
std::stringstream scp;
for (int i=0;i<pkthdr->len;i++) {
scp<<vec[i];
}
std::string mystr = std::string(scp.rdbuf()->str());
std::cout << "WAS: " << packet << std::endl;
std::cout << "GOOD: " << scp.str() << std::endl;
std::cout << "BAD: " << scp.str().c_str() << std::endl;
std::cout << "TEST: " << mystr.size() << std::endl;
assert(mystr.size() == pkthdr->len);
}
Results:
WAS: prints nothing (guess there is a pointer to const.. case)
GOOD: prints data
BAD: prints nothing
TEST, assert: prints that mystr.size() is equal to passed unsigned char size.
I tried:
string.assign(scp.rdbuf());
memcpy(char, scp.str(), 10);
different methods of creating/allocating temporary chars, strings
No help.. it is wanted to get a std::cout'able std::string that contains data, (which was picked from foo, which was unsigned char, which was packet data).
Guessing either the original foo may not be null-terminated, or the problem is something like this - simple, but can't get in.. what are the things to look for here?
(this code is another attempt to use libpcap, just to print packets in C++ way, without using known C++ magic wrappers like libpcapp).
For a quick test, throw in a check for scp.str().size() == strlen(scp.str().c_str()) to see if there are embedded '\0' characters in the string, which is what I suspect is happening.
I think you're going about this the wrong way. It looks like you're dealing with binary data here, in which case you can't expect to meaningfully output it to the screen as text. What you really need is a hex dump.
const unsigned char* ucopy = packet;
std::ios_base::fmtflags old_flags = std::cout.flags();
std::cout.setf(std::ios::hex, std::ios::basefield);
for (const unsigned char* p = ucopy, *e = p + pkthdr->len; p != e; ++p) {
std::cout << std::setw(2) << std::setfill('0') << static_cast<unsigned>(*p) << " ";
}
std::cout.flags(old_flags);
This will output the data byte-by-byte, and let you examine the individual hex values of the binary data. A null byte will simply be output as 00.
Check std::cout.good() after the failed output attempt. My guess is that there's some failure on output (i.e. trying to write a nonprintable character to the console), which is setting failbit on cout.
Also check to ensure the string does not start with a NULL, which would cause empty output to be the expected behavior :)
(Side note, please use reinterpret_cast for unsigned char *ucopy = (unsigned char*)packet; if you're in C++ ;) )
Is there an easy way to indent the output going to an ofstream object? I have a C++ character array that is null terminate and includes newlines. I'd like to output this to the stream but indent each line with two spaces. Is there an easy way to do this with the stream manipulators like you can change the base for integer output with special directives to the stream or do I have to manually process the array and insert the extra spaces manually at each line break detected?
Seems like the string::right() manipulator is close:
http://www.cplusplus.com/reference/iostream/manipulators/right/
Thanks.
-William
This is the perfect situation to use a facet.
A custom version of the codecvt facet can be imbued onto a stream.
So your usage would look like this:
int main()
{
/* Imbue std::cout before it is used */
std::ios::sync_with_stdio(false);
std::cout.imbue(std::locale(std::locale::classic(), new IndentFacet()));
std::cout << "Line 1\nLine 2\nLine 3\n";
/* You must imbue a file stream before it is opened. */
std::ofstream data;
data.imbue(indentLocale);
data.open("PLOP");
data << "Loki\nUses Locale\nTo do something silly\n";
}
The definition of the facet is slightly complex.
But the whole point is that somebody using the facet does not need to know anything about the formatting. The formatting is applied independent of how the stream is being used.
#include <locale>
#include <algorithm>
#include <iostream>
#include <fstream>
class IndentFacet: public std::codecvt<char,char,std::mbstate_t>
{
public:
explicit IndentFacet(size_t ref = 0): std::codecvt<char,char,std::mbstate_t>(ref) {}
typedef std::codecvt_base::result result;
typedef std::codecvt<char,char,std::mbstate_t> parent;
typedef parent::intern_type intern_type;
typedef parent::extern_type extern_type;
typedef parent::state_type state_type;
int& state(state_type& s) const {return *reinterpret_cast<int*>(&s);}
protected:
virtual result do_out(state_type& tabNeeded,
const intern_type* rStart, const intern_type* rEnd, const intern_type*& rNewStart,
extern_type* wStart, extern_type* wEnd, extern_type*& wNewStart) const
{
result res = std::codecvt_base::noconv;
for(;(rStart < rEnd) && (wStart < wEnd);++rStart,++wStart)
{
// 0 indicates that the last character seen was a newline.
// thus we will print a tab before it. Ignore it the next
// character is also a newline
if ((state(tabNeeded) == 0) && (*rStart != '\n'))
{
res = std::codecvt_base::ok;
state(tabNeeded) = 1;
*wStart = '\t';
++wStart;
if (wStart == wEnd)
{
res = std::codecvt_base::partial;
break;
}
}
// Copy the next character.
*wStart = *rStart;
// If the character copied was a '\n' mark that state
if (*rStart == '\n')
{
state(tabNeeded) = 0;
}
}
if (rStart != rEnd)
{
res = std::codecvt_base::partial;
}
rNewStart = rStart;
wNewStart = wStart;
return res;
}
// Override so the do_out() virtual function is called.
virtual bool do_always_noconv() const throw()
{
return false; // Sometime we add extra tabs
}
};
See: Tom's notes below
Well this is not the answer I'm looking for, but in case there is no such answer, here is a way to do this manually:
void
indentedOutput(ostream &outStream, const char *message, bool &newline)
{
while (char cur = *message) {
if (newline) {
outStream << " ";
newline = false;
}
outStream << cur;
if (cur == '\n') {
newline = true;
}
++message;
}
}
A way to add such feature would be to write a filtering streambuf (i.e. a streambuf which forwards the IO operation to another streambuf but manipulate the data transfered) which add the indentation as part of its filter operation. I gave an example of writing a streambuf here and boost provides a library to help in that.
If your case, the overflow() member would simply test for '\n' and then add the indent just after if needed (exactly what you have done in your indentedOuput function, excepted that newline would be a member of the streambuf). You could probably have a setting to increase or decrease the indent size (perhaps accessible via a manipulator, the manipulator would have to do a dynamic_cast to ensure that the streambuf associated to the stream is of the correct type; there is a mechanism to add user data to stream -- basic_ios::xalloc, iword and pword -- but here we want to act on the streambuf).
I've had good success with Martin's codecvt facet based suggestion, but I had problems using it on std::cout on OSX, since by default this stream uses a basic_streambuf based streambuf which ignores the imbued facet. The following line switches std::cout and friends to use a basic_filebuf based streambuf, which will use the imbued facet.
std::ios::sync_with_stdio(false);
With the associated side effect that the iostream standard stream objects may operate independently of the standard C streams.
Another note is since this facet does not have a static std::locale::id, which meant that calling std::has_facet<IndentFacet> on the locale always returned true. Adding a std::local::id meant that the facet was not used, since basic_filebuf looks for the base class template.
There is no simple way, but a lot has been written about the complex
ways to achieve this. Read this article for a good explanation of
the topic. Here is another article, unfortunately in German. But
its source code should help you.
For example you could write a function which logs a recursive structure. For each level of recursion the indentation is increased:
std::ostream& operator<<(std::ostream& stream, Parameter* rp)
{
stream << "Parameter: " << std::endl;
// Get current indent
int w = format::get_indent(stream);
stream << "Name: " << rp->getName();
// ... log other attributes as well
if ( rp->hasParameters() )
{
stream << "subparameter (" << rp->getNumParameters() << "):\n";
// Change indent for sub-levels in the hierarchy
stream << format::indent(w+4);
// write sub parameters
stream << rp->getParameters();
}
// Now reset indent
stream << format::indent(w);
return stream;
}
I have generalized Loki Astarti's solution to work with arbitrary indentation levels. The solution has a nice, easy to use interface, but the actual implementation is a little fishy. It can be found on github:https://github.com/spacemoose/ostream_indenter
There's a more involved demo in the github repo, but given:
#include "indent_facet.hpp"
/// This probably has to be called once for every program:
// http://stackoverflow.com/questions/26387054/how-can-i-use-stdimbue-to-set-the-locale-for-stdwcout
std::ios_base::sync_with_stdio(false);
// This is the demo code:
std::cout << "I want to push indentation levels:\n" << indent_manip::push
<< "To arbitrary depths\n" << indent_manip::push
<< "and pop them\n" << indent_manip::pop
<< "back down\n" << indent_manip::pop
<< "like this.\n" << indent_manip::pop;
}
It produces the following output:
I want to push indentation levels:
To arbitrary depths
and pop them
back down
like this.
I would appreciate any feedback as to the utility of the code.
Simple whitespace manipulator
struct Whitespace
{
Whitespace(int n)
: n(n)
{
}
int n;
};
std::ostream& operator<<(std::ostream& stream, const Whitespace &ws)
{
for(int i = 0; i < ws.n; i++)
{
stream << " ";
}
return stream;
}