Type of elements of std::string

L

Leslaw Bieniasz

Hi,

What is actually the type of elements of std::string?

I am trying to read the elements from a stream, in the following
way:

std::string str = "";
int c;

// Read string size
int n;
is >> n;

// Read string
for(int i=0; i<n; i++)
{
c = is.get();
str += c;
}

This seems to work, but the compiler (C++ Builder 6.0)
issues a warning at
c = is.get();
The warning is: Conversion may lose significant digits

On the other hand, if I switch to "char" instead of "int"
it seems that the code does not work.

How to write the code that does exactly the same thing
but without the warning?

Leslaw
 
R

Richard Herring

Hi,

What is actually the type of elements of std::string?
char.


I am trying to read the elements from a stream, in the following
way:

std::string str = "";
int c;

// Read string size
int n;
is >> n;

// Read string
for(int i=0; i<n; i++)
{
c = is.get();
str += c;
}

This seems to work, but the compiler (C++ Builder 6.0)
issues a warning at
c = is.get();
The warning is: Conversion may lose significant digits

Are you sure the warning isn't at the following line? std::string
doesn't have an operator+= which takes an int, and int to char is a
conversion that might lose significance.
On the other hand, if I switch to "char" instead of "int"
it seems that the code does not work.

What do you mean by "does not work"?
How to write the code that does exactly the same thing
but without the warning?
Understand how istream::get() reports errors.
 
L

Leslaw Bieniasz

Are you sure the warning isn't at the following line? std::string doesn't
have an operator+= which takes an int, and int to char is a conversion that
might lose significance.

Well, I understand that, but the essential question is how to read
the elements of std::string correctly, if std::string contains char,
whereas get() returns int. This looks like some sort of incompatibility.
Understand how istream::get() reports errors.

Surely I am not asking how to cheat the compiler to not to get messages,
but how to do things correctly.

Leslaw
 
R

Richard Herring

Well, I understand that, but the essential question is how to read
the elements of std::string correctly, if std::string contains char,
whereas get() returns int. This looks like some sort of incompatibility.

Do you understand *why* get() returns int, and what subset of possible
int values it can return? That's the point of my question below:
Surely I am not asking how to cheat the compiler to not to get messages,
but how to do things correctly.
Good. Then you should be reading an int from get(), separating out the
values that represent characters from those which don't, appending the
chars to the string and doing something else with the non-chars.
 
L

Leslaw Bieniasz

Do you understand *why* get() returns int, and what subset of possible int
values it can return? That's the point of my question below:

Yes, that's the point. I do not understand why get() returns int. If
get() is supposed to read successive bytes, then I would expect it
to return char. What are the cases when it returns int?
Is this EOF, or what else?
Good. Then you should be reading an int from get(), separating out the values
that represent characters from those which don't, appending the chars to the
string and doing something else with the non-chars.

Do you mean casting from int to char? This removes the warning message
and from my brief test seems to work OK, but how can I be sure if
it always works correctly?

Leslaw
 
R

Richard Herring

Yes, that's the point. I do not understand why get() returns int. If
get() is supposed to read successive bytes, then I would expect it
to return char. What are the cases when it returns int?
Is this EOF, or what else?

EOF. Read the documentation.
Do you mean casting from int to char?

Or any other form of conversion.
This removes the warning message
and from my brief test seems to work OK, but how can I be sure if
it always works correctly?

By only converting when you know that the value is in the range valid
for char.
 
J

Jerry Coffin

Hi,

What is actually the type of elements of std::string?

char. Specifically, the definition of std::string looks like:
typedef basic_string said:
I am trying to read the elements from a stream, in the following
way:

std::string str = "";
int c;

// Read string size
int n;
is >> n;

// Read string
for(int i=0; i<n; i++)
{
c = is.get();
str += c;
}

Hmm...I think I'd do this more like:

int n;
is >> n;

std::string str(n, ' ');
is.read(&str[0], n);

This should eliminate the warning(s), and if there's a difference in
efficiency, I'd guess it's more likely to favor this version than the
other. In theory, this isn't entirely portable -- the current
standard doesn't guarantee that std::string will use contiguous
storage for the characters. In reality, current implementations do
use contiguous storage, and the next version of the standard will
require it, so there's not really much chance of a new implementation
that uses non-contiguous storage.
 
J

James Kanze

char. Specifically, the definition of std::string looks like:
typedef basic_string<char> string;
Hmm...I think I'd do this more like:
int n;
is >> n;
std::string str(n, ' ');
is.read(&str[0], n);
This should eliminate the warning(s), and if there's a
difference in efficiency, I'd guess it's more likely to favor
this version than the other. In theory, this isn't entirely
portable -- the current standard doesn't guarantee that
std::string will use contiguous storage for the characters. In
reality, current implementations do use contiguous storage,
and the next version of the standard will require it, so
there's not really much chance of a new implementation that
uses non-contiguous storage.

What happens if there aren't n characters left to read? (And in
fact, I don't know. I practically never use istream::read, and
I don't have any documentation handy to check. But it's
obviously a case which has to be considered.)

More generally, considering the first algorithm: the
no-argument form of istream::get returns an int in order to
return out of band data, e.g. EOF. Once that data has been
tested for and excluded, the resulting value must be converted
to a char. Formally, a rather complex operation, since the
resulting value is in the range 0...UCHAR_MAX, which might not
fit into a char (and if the results don't fit, the behavior is
implementation defined, and might result in a signal).
Practically, implementations which use signed plain char will
always ensure that this works, given that it is such a standard
idiom (in C, at least). But if you really want to avoid it,
something like:

char ch;

// ...
if ( input.get( ch ) ) {
// succeeded, you can safely use ch...
} else {
// error or end of file, the contents of
// ch are unchanged.
}
 
J

Jerry Coffin

[ ... ]
std::string str(n, ' ');
is.read(&str[0], n);

[ ... ]
What happens if there aren't n characters left to read? (And in
fact, I don't know. I practically never use istream::read, and
I don't have any documentation handy to check. But it's
obviously a case which has to be considered.)

It returns the stream, which will have its failbit set if the read
failed (i.e., if it couldn't read as many characters as requested).
Given that the file specified the length, chances are pretty good
that the proper reaction is to log the error and abort, but depending
on what data it's trying to read, it might be able to live with
partial input, request the input from another source, or who knows
what.

Unlike fread, however, istream::read does NOT indicate how many
characters were read, so if (for example) trailing blanks in the
input were significant, and you really needed to distinguish them
from the string's initial value, this method probably wouldn't work
well (unless you could initialize the string to some other value you
knew wouldn't come from the input).
 
J

James Kanze

Your insistence on describing the behaviour of rare corner
case implementations is unhelpful as it confuses the issue,
the fact that char ch = (unsigned char) foo; is implementation
defined behaviour is not justification for eschewing the use
of istream::read().

I never said it was (and I do use istream::read and
istream::write). Still, a competent programmer will want to
understand what he's doing, and what the restrictions and the
trade-offs are.
Please rejoin the real world.

In the real world, not every machine is a PC.
 
J

Jerry Coffin

[ ... ]
istream::gcount() will tell you how many characters were read by
the last call to istream::read

Ah, quite right. I should have thought of that...
 

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,755
Messages
2,569,536
Members
45,008
Latest member
HaroldDark

Latest Threads

Top