istringstream question

L

Luther Baker

Hi,

My question is regarding std::istringstream. I am serializing data to
an ostringstream and the resulting buffer turns out just fine.

But, when I try the reverse, when the istringstream encounters the two
byte shorts, it either thinks it has reached the null terminator? or
eof and consequently stops reading values back in. It doesn't matter
whether or not I use the std::ios::binary flag when opening the
istringstream or the readsome method which does in-fact, not report
eof. It still can't build the shorts back up.

Any suggestions would be appreciated. Here is a brief example:


#include <cstring>
#include <sstream>

int
main(int argc, char** argv)
{
typedef unsigned short uint;

char* key = new char[8];
strncpy (key, "the key", 7)[7] = '\0';
uint var1 = 'a';
uint var2 = 'b';

std::eek:stringstream os;
os.write(key, 8);
os.write(reinterpret_cast<const char*>(&var1), sizeof(var1));
os.write(reinterpret_cast<const char*>(&var2), sizeof(var2));
std::cout << "stream string: " << os.str() << std::endl;
std::cout << "stream c_str: " << os.str().c_str() << std::endl;

char* keytwo = new char[8];
keytwo[7] = 0;
uint feedme1 = 0;
uint feedme2 = 0;

//
// Here is where my question lies - how to initialize istringstream?
//
std::istringstream is (os.str().c_str(), std::ios::binary);
is.read(keytwo, 8);
std::cout << "\n\nkeytwo: " << keytwo << std::endl;
if (is.eof())
{
std::cout << "END OF FILE!!!" << std::endl;
}

is.read(reinterpret_cast<char*>(&feedme1), sizeof(feedme1));
std::cout << "feedme1: " << feedme1 << std::endl;

is.read(reinterpret_cast<char*>(&feedme2), sizeof(feedme2));
std::cout << "feedme2: " << feedme2 << std::endl;

//
// but it is clear the both shorts are present in the c_str
//
for (int i = 0; i < 12; ++i)
{
std::cout << os.str().c_str() << std::endl;
}

//
// and my favorite way to see what's happening
//
for (int i = 0; i < 12; ++i)
{
std::cout << (int)os.str().c_str() << std::endl;
}

delete [] key;
delete [] keytwo;

return 0;
}



Thanks,

-Luther
 
V

Victor Bazarov

Luther Baker said:
My question is regarding std::istringstream. I am serializing data to
an ostringstream and the resulting buffer turns out just fine.

But, when I try the reverse, when the istringstream encounters the two
byte shorts, it either thinks it has reached the null terminator? or
eof and consequently stops reading values back in. It doesn't matter
whether or not I use the std::ios::binary flag when opening the
istringstream or the readsome method which does in-fact, not report
eof. It still can't build the shorts back up.

Any suggestions would be appreciated. Here is a brief example:


#include <cstring>
#include <sstream>

int
main(int argc, char** argv)
{
typedef unsigned short uint;

char* key = new char[8];
strncpy (key, "the key", 7)[7] = '\0';
uint var1 = 'a';
uint var2 = 'b';

std::eek:stringstream os;
os.write(key, 8);
os.write(reinterpret_cast<const char*>(&var1), sizeof(var1));
os.write(reinterpret_cast<const char*>(&var2), sizeof(var2));
std::cout << "stream string: " << os.str() << std::endl;
std::cout << "stream c_str: " << os.str().c_str() << std::endl;

char* keytwo = new char[8];
keytwo[7] = 0;
uint feedme1 = 0;
uint feedme2 = 0;

//
// Here is where my question lies - how to initialize istringstream?
//
std::istringstream is (os.str().c_str(), std::ios::binary);

As soon as you use .c_str() here, you lose everything after the first
zero character, which becomes the terminator. You need to use the
string directly:

std::istringstream is(os.str(), std::ios::binary);

HTH
is.read(keytwo, 8);
std::cout << "\n\nkeytwo: " << keytwo << std::endl;
if (is.eof())
{
std::cout << "END OF FILE!!!" << std::endl;
}

is.read(reinterpret_cast<char*>(&feedme1), sizeof(feedme1));
std::cout << "feedme1: " << feedme1 << std::endl;

is.read(reinterpret_cast<char*>(&feedme2), sizeof(feedme2));
std::cout << "feedme2: " << feedme2 << std::endl;

//
// but it is clear the both shorts are present in the c_str
//
for (int i = 0; i < 12; ++i)
{
std::cout << os.str().c_str() << std::endl;
}

//
// and my favorite way to see what's happening
//
for (int i = 0; i < 12; ++i)
{
std::cout << (int)os.str().c_str() << std::endl;
}

delete [] key;
delete [] keytwo;

return 0;
}



Thanks,

-Luther
 
L

Luther Baker

Victor said:
Luther Baker said:
My question is regarding std::istringstream. I am serializing data to
an ostringstream and the resulting buffer turns out just fine. ....
std::eek:stringstream os;
os.write(key, 8);
os.write(reinterpret_cast<const char*>(&var1), sizeof(var1));
os.write(reinterpret_cast<const char*>(&var2), sizeof(var2));
std::cout << "stream string: " << os.str() << std::endl;
std::cout << "stream c_str: " << os.str().c_str() << std::endl;

char* keytwo = new char[8];
keytwo[7] = 0;
uint feedme1 = 0;
uint feedme2 = 0;

//
// Here is where my question lies - how to initialize istringstream?
//
std::istringstream is (os.str().c_str(), std::ios::binary);


As soon as you use .c_str() here, you lose everything after the first
zero character, which becomes the terminator. You need to use the
string directly:

std::istringstream is(os.str(), std::ios::binary);

Ah.

So - for my real project, I have the following:

void AnObject::DeSerialize(const void* buffer)
{
std::istringstream ( ? ... );
....
}

Following your lead, I'll try to create a string.

std::string str(reinterpret_cast<const char*>(buffer));

Nope. Loses the tail end ... (NULL terminated)

const int size = X;
std::string str(size, size)
for (int i = 1; i < size; ++i)
{
str = buffer;
}

Ah ... that works! And I do, in fact, know exactly how many bytes I need
to copy.

Would you suggest a smoother way or different approach now that you see
a bit more of what I'm after?

Thanks,

-Luther
 
V

Victor Bazarov

Luther Baker said:
Victor said:
Luther Baker said:
My question is regarding std::istringstream. I am serializing data to
an ostringstream and the resulting buffer turns out just fine. ...
std::eek:stringstream os;
os.write(key, 8);
os.write(reinterpret_cast<const char*>(&var1), sizeof(var1));
os.write(reinterpret_cast<const char*>(&var2), sizeof(var2));
std::cout << "stream string: " << os.str() << std::endl;
std::cout << "stream c_str: " << os.str().c_str() << std::endl;

char* keytwo = new char[8];
keytwo[7] = 0;
uint feedme1 = 0;
uint feedme2 = 0;

//
// Here is where my question lies - how to initialize istringstream?
//
std::istringstream is (os.str().c_str(), std::ios::binary);


As soon as you use .c_str() here, you lose everything after the first
zero character, which becomes the terminator. You need to use the
string directly:

std::istringstream is(os.str(), std::ios::binary);

Ah.

So - for my real project, I have the following:

void AnObject::DeSerialize(const void* buffer)
{
std::istringstream ( ? ... );
....
}

Following your lead, I'll try to create a string.

std::string str(reinterpret_cast<const char*>(buffer));

Nope. Loses the tail end ... (NULL terminated)

const int size = X;
std::string str(size, size)
for (int i = 1; i < size; ++i)
{
str = buffer;
}


Don't you mean

std::string str(buffer, size);

?
Ah ... that works! And I do, in fact, know exactly how many bytes I need
to copy.

Would you suggest a smoother way or different approach now that you see
a bit more of what I'm after?

I am not sure what way would be "smoother". If you need to have meaningful
zeroes in the "buffer", then you cannot hope to call deserialise without
passing the size of the stream in, btw.

void AnObject::Deserialize(const char *buffer)
{
std::istringstream is(std::string(buffer, size), ios::binary);
// now read from it
}

Victor
 
M

Mike Wahler

Luther Baker said:
Victor said:
Luther Baker said:
My question is regarding std::istringstream. I am serializing data to
an ostringstream and the resulting buffer turns out just fine. ...
std::eek:stringstream os;
os.write(key, 8);
os.write(reinterpret_cast<const char*>(&var1), sizeof(var1));
os.write(reinterpret_cast<const char*>(&var2), sizeof(var2));
std::cout << "stream string: " << os.str() << std::endl;
std::cout << "stream c_str: " << os.str().c_str() << std::endl;

char* keytwo = new char[8];
keytwo[7] = 0;
uint feedme1 = 0;
uint feedme2 = 0;

//
// Here is where my question lies - how to initialize istringstream?
//
std::istringstream is (os.str().c_str(), std::ios::binary);


As soon as you use .c_str() here, you lose everything after the first
zero character, which becomes the terminator. You need to use the
string directly:

std::istringstream is(os.str(), std::ios::binary);

Ah.

So - for my real project, I have the following:

void AnObject::DeSerialize(const void* buffer)
{
std::istringstream ( ? ... );
....
}

Following your lead, I'll try to create a string.

std::string str(reinterpret_cast<const char*>(buffer));

Nope. Loses the tail end ... (NULL terminated)

const int size = X;
std::string str(size, size)
for (int i = 1; i < size; ++i)
{
str = buffer;
}

Ah ... that works! And I do, in fact, know exactly how many bytes I need
to copy.

Would you suggest a smoother way or different approach now that you see
a bit more of what I'm after?


const char *p = static_cast<const char *>buffer;
std::string str(p, p + X);

-Mike
 
L

Luther Baker

Victor said:
....
const int size = X;
std::string str(size, size)
for (int i = 1; i < size; ++i)
{
str = buffer;
}



Don't you mean

std::string str(buffer, size); ....

I am not sure what way would be "smoother". If you need to have meaningful
zeroes in the "buffer", then you cannot hope to call deserialise without
passing the size of the stream in, btw.

void AnObject::Deserialize(const char *buffer)
{
std::istringstream is(std::string(buffer, size), ios::binary);
// now read from it
}


For some reason, I thought that *std::string str(buffer, size);* would
have strncpy semantics and stop copying buffer at the first null. But as
I'm sure you're aware, it doesn't.

When I said "smoother" I guess I meant more elegant. It seems clunky to
have to create a std::string to get a std::istringstream interface over
the buffer - but I guess it is a *string* stream.

Many Thanks,

-Luther
 
L

Luther Baker

Mike said:
const char *p = static_cast<const char *>buffer;
std::string str(p, p + X);

Does that imply

string::string (const char* cstrBegin, const char* cstrEnd);

Josuttis pg.509 left that one out! unless that is silently turned into

string::string (InputIterator beg, InputIterator end);

Thanks for your insight,

-Luther
 
J

John Harrison

When I said "smoother" I guess I meant more elegant. It seems clunky to
have to create a std::string to get a std::istringstream interface over
the buffer - but I guess it is a *string* stream.

Use an istrstream instead. Reading from a fixed size buffer is about the
only reasonable use of strstream.

john
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,999
Messages
2,570,243
Members
46,838
Latest member
KandiceChi

Latest Threads

Top