Go Back   Rhinocerus > Newsgroup > Newsgroup comp.language.c++ > Newsgroup comp.language.c++.moderated

Reply
 
Thread Tools Display Modes
  #1 (permalink)  
Old 11-04-2005, 10:05 AM
mzdude
Guest
 
Posts: n/a
Default X stream extraction

At our shop, programming guidelines strongly recommend initializing
variables at the point of declaration, and making them const whenever
possible. Some examples are:

const int min_hours = 6;
const double max_pay = 400.0;

etc.

So there is great debate when reading and populating variables from an
input stream.

// Example of code frowned upon. Variable not initialized
size_t x;
input_stream >> x;

// Example acceptable but inefficient code
size_t x = 0; // initialized, but immediately over written
input_stream >> x;

// Possible code
const size_t x = Read<size_t>( input_stream );

Is there any other way to declare and initialize variables from an
input stream. Especially const variables.

The above looks OK until you begin looking at the Read()

template< typename T >
T Read( std::istream &is )
{
T x; // unitialized but unlikely to break during maintenance
is >> x;
return x;
}

The template both doesn't initialize x and is inefficient when reading
in objects. Think
std::string x = Read<std::string>(input_stream);
or if you prefer the Stephen Dewherst recomendation
std::string x( Read<std::string>(input_stream) );

In the end, the code should be extremely safe and extremely efficient
;^) (sorry for the puns X stream extraction )


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
Alt Today
Advertising
 
and become member of Rhinocerus
Standard Sponsored Links

  #2 (permalink)  
Old 11-05-2005, 10:33 AM
Valentin.Samko
Guest
 
Posts: n/a
Default Re: X stream extraction

mzdude wrote:
> // Example acceptable but inefficient code
> size_t x = 0; // initialized, but immediately over written
> input_stream >> x;


The CPU time to zero initialise 'x' is negligible compared to the CPU
time to read that integer from the string. I wouldn't warry about this.
Also, don't forget that the >> operation may fail.

> const size_t x = Read<size_t>( input_stream );

And what if the read operation fails?

> Is there any other way to declare and initialize variables from an
> input stream. Especially const variables.

If its a const variable, read in a function and return the value.

> template< typename T >
> T Read( std::istream &is )
> {
> T x; // unitialized but unlikely to break during maintenance

The main problem I have with this is the "unlikely" bit. And again, I
would warry about the CPU time to initialise a variable.
> is >> x;
> return x;
> }


> The template both doesn't initialize x and is inefficient when reading
> in objects.

This depends on whether your compiler does NRVO.

--

Valentin Samko - http://www.valentinsamko.com


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #3 (permalink)  
Old 11-05-2005, 10:39 AM
Ulrich Eckhardt
Guest
 
Posts: n/a
Default Re: X stream extraction

mzdude wrote:
> At our shop, programming guidelines strongly recommend initializing
> variables at the point of declaration, and making them const whenever
> possible.


I hope those guidelines also mention that
- objects with a proper constructor don't need external initialisation
- the reason is that accessing an uninitalized value leads to a) all kinds
of behaviour and b) is undefined behaviour by the standard.
IOW, use of uninitialized values must be avoided, because it breaks code in
unpredictable ways.

> // Example of code frowned upon. Variable not initialized
> size_t x;
> input_stream >> x;
>


Inacceptable by my standards, you fail to check if reading succeeded. That
might be done later in that example, but when I see this:

> // Possible code
> const size_t x = Read<size_t>( input_stream );
>

[...]
>
> template< typename T >
> T Read( std::istream &is )
> {
> T x; // unitialized but unlikely to break during maintenance
> is >> x;
> return x;
> }


.... I see that it isn't done. Bad idea.

Use this body for Read<T>() and you're much safer:
T x;
if(!(is>>x))
throw_exception();
return x;

Looking at the coding guidelines, this also doesn't initialize x, but it is
easy to see that either it is initialized by reading from a stream or it is
unused because the function leaves via an exception. To me, this is enough
justification to not apply that part of the coding guidelines here.

Uli


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #4 (permalink)  
Old 11-05-2005, 10:40 AM
Tony Delroy
Guest
 
Posts: n/a
Default Re: X stream extraction

A good programmer learns to make the right compromises, and this
attempt at absolute rigour suggests a misguided excess to me. It
arbitrarily prioritises const-ness and assignment at definition
independent of context. For example...

> // Example of code frowned upon. Variable not initialized
> size_t x;
> input_stream >> x;


...._should_ be frowned upon, but because there's no evidence that the
streaming operation is tested for success. In many programs, a clear
expression of stream I/O error handling is a bigger concern than
const-ness and assignment at definition.

size_t x;

if (input_stream >> x)
...
else
...;

Sure, non-localised error handling is possible after setting the stream
to throw on error, which again changes the context and balance of
priorities. Increasing the number of variables may tip the balance yet
again:

const size_t x = Read<size_t>( input_stream );
const size_t y = Read<size_t>( input_stream );

captures the I/O intent less succinctly than:

size_t x, y;

if (input_stream >> x >> y) ...;

As for uninitialised variables: it's a matter of localisation. Is the
following line (perhaps after a spacing line) local enough to be
instinctively reviewed when checking the code? I'd argue "yes": if I
see an uninitialised variable the first thing I do is scan the next
couple lines to see where it's assigned. I'll be suspicious if it's
not set there somewhere. Is the lack of const acceptable? I'd argue
it's unfortunate, but sometimes a lesser evil.

// Example acceptable but inefficient code
size_t x = 0; // initialized, but immediately over written
input_stream >> x;

This is plain silly, as it implies that there's some point or
significance in assigning the 0. In general, if a streaming input
operation fails, the value being read into may still be changed. On
the other hand, if unchanged and uninitialised, then at least there's a
chance of tools like purify and valgrind detecting an eventual read
from uninitialised memory.

operator>> for inbuilt types is designed to stream into pre-existing
objects, and operator>> for user-defined types should conform to
expectation.

My advice:

- _consider_ (but don't jump at the opportunity to) provide a
constructor from a stream for non-trivial user-defined types, where
there's _significant_ cost in default construction (which is pretty
rare, and even rarer if constructor and assignment operator happen to
be inline and you're using optimisation)

- use your Read<> template where it doesn't obfuscate I/O intent or
error handling,

- use plain old "input_stream >> " directly to uninitialised, non-const
variables otherwise.

Cheers,

Tony


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #5 (permalink)  
Old 11-05-2005, 05:36 PM
Greg Herlihy
Guest
 
Posts: n/a
Default Re: X stream extraction

mzdude wrote:
> At our shop, programming guidelines strongly recommend initializing
> variables at the point of declaration, and making them const whenever
> possible. Some examples are:
>
> const int min_hours = 6;
> const double max_pay = 400.0;
>
> etc.
>
> So there is great debate when reading and populating variables from an
> input stream.
>
> // Example of code frowned upon. Variable not initialized
> size_t x;
> input_stream >> x;
>
> // Example acceptable but inefficient code
> size_t x = 0; // initialized, but immediately over written
> input_stream >> x;


Alternately:

size_t x();
input_stream >> x;

> // Possible code
> const size_t x = Read<size_t>( input_stream );
>
> Is there any other way to declare and initialize variables from an
> input stream. Especially const variables.
>
> The above looks OK until you begin looking at the Read()
>
> template< typename T >
> T Read( std::istream &is )
> {
> T x; // unitialized but unlikely to break during maintenance
> is >> x;
> return x;
> }


Again, it's unlikely that initialization x would measurably affect
performance:

template< typename T >
T Read( std::istream &is )
{
T x();
is >> x;
return x;
}

Note that the () syntax (and even the ~x() syntax) is still legal when
T is a POD type.

> The template both doesn't initialize x and is inefficient when reading
> in objects. Think
> std::string x = Read<std::string>(input_stream);
> or if you prefer the Stephen Dewherst recomendation
> std::string x( Read<std::string>(input_stream) );
>
> In the end, the code should be extremely safe and extremely efficient
> ;^) (sorry for the puns X stream extraction )


Actually, because the Read() routine always returns the same variable
it is eligible for the named Return Value Optimization (NRVO). With
NRVO, Read() would be close to optimally efficient - more efficient
than a version of Read() that passed in and returned the T object to
hold the result, for instance.

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #6 (permalink)  
Old 11-05-2005, 05:39 PM
werasm
Guest
 
Posts: n/a
Default Re: X stream extraction


mzdude wrote:
> At our shop, programming guidelines strongly recommend initializing
> variables at the point of declaration, and making them const whenever
> possible. Some examples are:
>
> const int min_hours = 6;
> const double max_pay = 400.0;
>
> etc.
>
> So there is great debate when reading and populating variables from an
> input stream.
>
> // Example of code frowned upon. Variable not initialized
> size_t x;
> input_stream >> x;


Yes, I would consider frowning upon it to, for who's to say the data
associated with input_stream is compatible with x, in which case
the write to x would fail, leaving it in an uninitialised state.

>
> // Example acceptable but inefficient code
> size_t x = 0; // initialized, but immediately over written
> input_stream >> x;


Wow, you not gaining much wrt efficiency. How do you know
"input_stream >> x" did what it is supposed to - example:

console > Please any a number:

user > y <cr>

App:
float fUser;
cin >> fUser; //Hmmm, what is fUser now?

I do understand your problem though. You don't want to be inefficient
and
yet you want to remain safe...

>
> // Possible code
> const size_t x = Read<size_t>( input_stream );
>
> Is there any other way to declare and initialize variables from an
> input stream. Especially const variables.
>
> The above looks OK until you begin looking at the Read()
>
> template< typename T >
> T Read( std::istream &is )
> {
> T x; // unitialized but unlikely to break during maintenance
> is >> x;
> return x;
> }


Yes, when calling Read you have to assume it does the right thing. How
do we initialise x efficiently in Read? I've had a look at boost
intialisers, and it seems
that can be used for this case. Read then becomes:

template< typename T >
T Read( std::istream &is )
{
boost::value_intialized<T> x;
is >> x;
return x;
}

>
> The template both doesn't initialize x and is inefficient when reading
> in objects. Think
> std::string x = Read<std::string>(input_stream);
> or if you prefer the Stephen Dewherst recomendation
> std::string x( Read<std::string>(input_stream) );


Now you can be sure that Read does initialize x, and Dewherst's
recomendation
can be met :-).

>
> In the end, the code should be extremely safe and extremely efficient


Yes, which it now becomes.

> ;^) (sorry for the puns X stream extraction )


Regards,

Werner


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #7 (permalink)  
Old 11-05-2005, 05:40 PM
mzdude
Guest
 
Posts: n/a
Default Re: X stream extraction

Tony Delroy wrote:
> A good programmer learns to make the right compromises, and this
> attempt at absolute rigour suggests a misguided excess to me. It
> arbitrarily prioritises const-ness and assignment at definition
> independent of context. For example...
>
> > // Example of code frowned upon. Variable not initialized
> > size_t x;
> > input_stream >> x;

>
> ..._should_ be frowned upon, but because there's no evidence that the
> streaming operation is tested for success. In many programs, a clear
> expression of stream I/O error handling is a bigger concern than
> const-ness and assignment at definition.
>

Error handling was omitted for brevity. ... And yet so many
programmers tend to not check library function call results. It is
exactly that reason that I like to init variables on declaration. It
avoids all kinds of hard to track bugs. I find that being consistent
tends to help avoid whole classes of bugs.

It isn't misguided rigour to develop good programming habits. This is
one case where perhapse a good habit isn't enough. Or perhaps my habit
needs to be modified. :^)


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #8 (permalink)  
Old 11-05-2005, 05:41 PM
James Kanze
Guest
 
Posts: n/a
Default Re: X stream extraction

mzdude wrote:
> At our shop, programming guidelines strongly recommend
> initializing variables at the point of declaration, and making
> them const whenever possible. Some examples are:


> const int min_hours = 6;
> const double max_pay = 400.0;


> etc.


A good general rule.

> So there is great debate when reading and populating variables
> from an input stream.


> // Example of code frowned upon. Variable not initialized
> size_t x;
> input_stream >> x;


Nothing to frown upon. It's the exception to the rule.

> // Example acceptable but inefficient code
> size_t x = 0; // initialized, but immediately over written
> input_stream >> x;


I doubt that it makes a difference in actual run-time, so I
don't think ou can talk about inefficient code. On the other
hand, the initialization leads one to think that x can have the
value 0, and that the value 0 is in some way significant. The
code is thus misleading... unless some later code counts on x
being zero if the input fails. (I don't like that sort of
dependancy. I think that the standard guarantees that x is
unchanged if the >> operator fails, but that wasn't the case in
the classical iostream; in the classical iostream, the value of
x was undefined in case of input failure.)

> // Possible code
> const size_t x = Read<size_t>( input_stream );


> Is there any other way to declare and initialize variables
> from an input stream. Especially const variables.


No. It's pretty easy to create a Read function like the above,
but I don't see the point in it.

> The above looks OK until you begin looking at the Read()


> template< typename T >
> T Read( std::istream &is )
> {
> T x; // unitialized but unlikely to break during

maintenance
> is >> x;
> return x;
> }


> The template both doesn't initialize x and is inefficient when
> reading in objects. Think


> std::string x = Read<std::string>(input_stream);
> or if you prefer the Stephen Dewherst recomendation
> std::string x( Read<std::string>(input_stream) );


I'm afraid I don't see the inefficiency. On the other hand, I
don't see the problem with simply writing:

int x ;
input >> x ;

The variable isn't anything that the compiler can treat as const
(regardless of how it is initialized), and since the scope of
local variables is so small (a couple of lines, at most), the
human reader should have no problem keeping it straight.

> In the end, the code should be extremely safe and extremely
> efficient ;^) (sorry for the puns X stream extraction )


In the end, the code should be safe enough and efficient enough,
and extremely simply to understand and to modify. Going into
contortions to avoid violating a rule is missing the point of
the rule, which should be to make the code simpler to understand
and to modify.

The reason for the rule of initializing in the definition is, of
course, that it makes it much easier to see where and with what
the variable is initialized, and to ensure that a later
modification doesn't accidentally use the variable before it is
initialized. In this regard, the advantage is the physical
proximity, not the fact that it is a single statement, and there
is not much difference between:
int i = 1 ;
and
int i ;
i = 1 ;
except that it is much easier to write the first. When,
however, there is no way to write the first (e.g. when the
initialization is a >> operator), there's no problem with the
second. The important point is that there is nothing that
occurs between the two.

--
James Kanze mailto: james.kanze@free.fr
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 pl. Pierre Sémard, 78210 St.-Cyr-l'École, France +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #9 (permalink)  
Old 11-06-2005, 11:17 AM
Greg Herlihy
Guest
 
Posts: n/a
Default Re: X stream extraction

I noticed two mistakes in my earlier post. Lest anyone become confused,
here are the corrections:

>
> Alternately:
>
> size_t x();
> input_stream >> x;


I should have typed:

size_t x = size_t();
input_stream >> x;

Similarly, the Read function

>
> template< typename T >
> T Read( std::istream &is )
> {
> T x();
> is >> x;
> return x;
> }
>


should have been:

template< typename T >
T Read( std::istream &is )
{
T x = T();
is >> x;
return x;
}

Greg


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #10 (permalink)  
Old 11-07-2005, 09:49 AM
Alberto Ganesh Barbati
Guest
 
Posts: n/a
Default Re: X stream extraction

Tony Delroy wrote:
> // Example acceptable but inefficient code
> size_t x = 0; // initialized, but immediately over written
> input_stream >> x;
>
> This is plain silly, as it implies that there's some point or
> significance in assigning the 0. In general, if a streaming input
> operation fails, the value being read into may still be changed.


This is not true for arithmetic types. It's not self-evident from the
standard, but it's a consequence of the following statement of the
num_get<> facet (22.2.2.1.2/1):

"Effects: Reads characters from in, interpreting them according to
str.flags(), use_facet<ctype<charT> >(loc), and
use_facet<numpunct<charT> >(loc), where loc is str.getloc(). If an error
occurs, val is unchanged; otherwise it is set to the resulting value."

For std::string it's a bit different (21.3.7.9/1):

"Begins by constructing a sentry object k as if k were constructed by
typename basic_istream<charT,traits>::sentry k(is). If bool(k) is true,
it calls str.erase() and then extracts characters from is and appends
them to str as if by calling str.append(1,c). [...]"

If failure is detected by the sentry object, the target string remains
unchanged. However, if failure occurs after checking the sentry, the
string might indeed be modified. Notice that this kind of failure may
occur only if someone (for example underflow()) throws an exception,
with the end result of setting badbit but not failbit.

For char* the situation is similar to std::string.

> operator>> for inbuilt types is designed to stream into pre-existing
> objects, and operator>> for user-defined types should conform to
> expectation.


As shown above, apart from a very exceptional situation regarding
strings, operator>> is designed to leave the object unchanged on
failure, so operator>> for user-defined types should conform to *that*
expectation, IMHO. That means operator>> for UDTs should *not* stream
into pre-existing objects, because it would potentially leave an object
in an inconsistent state. Such inauspicious situation should be avoided
at all costs, even if doing so requires making a copy.

HTH,

Ganesh

[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
  #11 (permalink)  
Old 11-08-2005, 09:48 AM
kanze
Guest
 
Posts: n/a
Default Re: X stream extraction

Alberto Ganesh Barbati wrote:
> Tony Delroy wrote:
> > // Example acceptable but inefficient code
> > size_t x = 0; // initialized, but immediately over written
> > input_stream >> x;


> > This is plain silly, as it implies that there's some point
> > or significance in assigning the 0. In general, if a
> > streaming input operation fails, the value being read into
> > may still be changed.


> This is not true for arithmetic types. It's not self-evident
> from the standard, but it's a consequence of the following
> statement of the num_get<> facet (22.2.2.1.2/1):


> "Effects: Reads characters from in, interpreting them
> according to str.flags(), use_facet<ctype<charT> >(loc), and
> use_facet<numpunct<charT> >(loc), where loc is str.getloc().
> If an error occurs, val is unchanged; otherwise it is set to
> the resulting value."


Note that this guarantee was not present in pre-standard
implementations (although they may have worked like this).
Which means that old fogeys like myself have gotten into the
habit of not counting on it.

It's also worth asking your self what happens if at some later
date, you replace the int with a BigInteger class. Can you
count on the implementation of >> for BigInteger not modifying
the value in case of error?

> For std::string it's a bit different (21.3.7.9/1):


> "Begins by constructing a sentry object k as if k were
> constructed by typename basic_istream<charT,traits>::sentry
> k(is). If bool(k) is true, it calls str.erase() and then
> extracts characters from is and appends them to str as if by
> calling str.append(1,c). [...]"


> If failure is detected by the sentry object, the target string
> remains unchanged. However, if failure occurs after checking
> the sentry, the string might indeed be modified. Notice that
> this kind of failure may occur only if someone (for example
> underflow()) throws an exception, with the end result of
> setting badbit but not failbit.


> For char* the situation is similar to std::string.


> > operator>> for inbuilt types is designed to stream into
> > pre-existing objects, and operator>> for user-defined types
> > should conform to expectation.


> As shown above, apart from a very exceptional situation
> regarding strings, operator>> is designed to leave the object
> unchanged on failure, so operator>> for user-defined types
> should conform to *that* expectation, IMHO. That means
> operator>> for UDTs should *not* stream into pre-existing
> objects, because it would potentially leave an object in an
> inconsistent state. Such inauspicious situation should be
> avoided at all costs, even if doing so requires making a copy.


I agree with the "should", and that's the way I write my >>.
Given that historically, this wasn't a requirement, and that the
fact that it now a requirement doesn't seem to be widely known,
I'm not sure that I can count on all code actually being
written the way it should be.

I might add that I've never had any difficulty writing code
which didn't count on it. Most of the time, if the input didn't
succeed, I won't use the value anyway, and in the rare cases
where I might, it's pretty trivial to add the assignment of the
default value to the error handling branche.

All in all, I'd say that this is a case where the first rule of
the Internet applies: be liberal in what you accept, and
conservative in what you send. In this case, ensure that any >>
operators you write yourself obey the rule, but don't count on
it from other >> operators.

--
James Kanze GABI Software
Conseils en informatique orientée objet/
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34


[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

Reply With Quote
 
Reply

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are Off
Pingbacks are Off
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Re: String search and extraction Choate, Paul@DDS Newsgroup comp.soft-sys.sas 0 02-15-2006 03:52 PM
Re: String search and extraction Droogendyk, Harry Newsgroup comp.soft-sys.sas 0 02-15-2006 03:45 PM
Re: Ideas for soft-coding extraction macro Dunn, Toby Newsgroup comp.soft-sys.sas 1 12-10-2004 03:11 PM
how can i use SAS extraction data from CRSP =?big5?b?qkywfbth?= Newsgroup comp.soft-sys.sas 0 10-26-2004 10:17 AM
how can i use SAS to extraction data from CRSP. =?big5?b?qkywfbth?= Newsgroup comp.soft-sys.sas 0 10-26-2004 10:07 AM



All times are GMT. The time now is 12:15 AM.


Copyright ©2009

LinkBacks Enabled by vBSEO 3.3.0 RC2 © 2009, Crawlability, Inc.