Re: What is the output of this program?
* James Kanze:
Alf P. Steinbach wrote:
string ToUpper(const string& s1)
Class 'string' is undefined. For the sake of discussion,
assuming it is
'std::string'. This could have been avoided by not using a 'using'.
Uninformative name. 'result' would have been informative.
for (int i = 0; i < s1.size(); ++i)
'int' doesn't necessarily have large enough range.
But realistically, on a 32 bit machine, that won't really be a
problem. (Today. As memory becomes bigger, of course, it could
become reasonable to have strings longer than 231 characters.)
No, realistically, int is only guaranteed to be 16-bit, and the OP did
not state any particular target system: AFAIK most development is for
embedded systems (whether it's that way for C++, I don't know).
'isalpha' (assuming this is 'std::isalpha') may produce an unexpected
result if 'char' is signed.
It depends on what headers were included. Generally speaking,
std::isalpha() doesn't have this problem.
No, that's incorrect.
On the other hand, it
takes two arguments, so it is obviously not the one he is using.
No, there are two overloads of std::isalpha. "It" has one overload that
takes one argument, available from <cctype>, and one that takes two,
available from <locale>. The one with two arguments is not the one
called above with one argument.
If we assume ::isalpha, from the C header <ctype.h>, then it's
not an "unexpected result", it's undefined behavior.
No, the statement may produce an unexpected result, as I wrote, and it
is (for actual negative argument values except EOF) undefined behavior.
You are correct that it isn't an unexpected result. However, nobody
has maintained that it is, only that it may produce one, which it may.
also a potential thread safety issue, but in practice, it's not
No, the C++ standard does not address thread safety. Or threads, at
all. With any particular C++ implementation, thread library and calling
context there may be a thread safety issue or not.
This means Unpredictable Behavior.
According to the standard, undefined behavior.
But I agree that
the probability of anything other than just a random result is
No, I haven't stated that.
Argument should be casted to unsigned.
unsigned char. Casting it to unsigned isn't correct either, as
it can result in values like 0x7FFFFF62.
Yes. I think one who understands enough to do the cast will cast to the
correct unsigned type. Nevertheless, it should perhaps have been stated.
Unnecessary; this is the default.
Still, main is a special case; it's much clearer to be explicit.
Not as I see it, no, because what that statement is explicit about is to
indicate something that isn't true. The program does not ensure a
'main' return value that reflects success or failure, but the statement
implies that it does, that there's a possibility of some other exit
code. There's nothing clear about a statement that has no effect.
No catching of possible exception.
With all the undefined behavior, he couldn't catch them reliably
No, it's not a good idea to never indicate which way you're turning
(when driving a car) just because you're already in violation of the
traffic codes, e.g. by driving on the wrong side of the road. A bad
habit like never using the indicator, or whatever it's called in
English, will follow you when you learn about driving on the right side.
Seriously, I'm curious as to what you mean by this. For a lot
of simple programs, the default behavior of terminating in case
of an exception is quite acceptable. And the only way to catch
all exceptions is a "catch(...)"; what do you do in the catch
For me, that depends on the program. For a novice, log to std::cerr or
std::clog, and exit with code EXIT_FAILURE.
A mistake made me stare at the screen for a while ...
Impossible to guess /which/ mistake that was; many to choose from
Yes and no. Since he's also shown the set of test data, we know
that it doesn't actually contain values where the signedness of
char can cause problems. (The standard guarantees that all
characters in the basic execution set have positive encodings
when stored in a char.)
No, given all the errors we don't know that the test data exhaustively
tests all cases for the intended usage.
2. Don't use raw indexing  until you gain far more experience, use
(this catches bugs like forgetting to set the size of the
Use a good implementation of the STL which will core dump with
an error message in case of error.
Also, prefer iterators to . It's more idiomatic, and in this
case, when creating a string (or any other collection), the use
of push_back() is also so idiomatic that it should be second
push_back can be a tad inefficient on strings, because strings are
usually short, and for short sequences the reallocations, assuming
scaling of buffer size, are more frequent and thus more costly.
3. Do catch exceptions in 'main', report them on 'std::cerr' and in
that case return EXIT_FAILURE from 'main'
(this helps report e.g. an exception from 'at').
At least on the systems I work on, NOT catching an unexpected
exception is preferable. It also results in a "failure" (seen
from the OS side), but also gives a core dump which allows for
post mortem analysis; catching the exception prevents this.
Depends much on the system and the programmer. Of course Just In Time
symbolic debugging is preferable to a 1960's core dump... ;-) However,
for the novice the exception text will in most cases be enough to get a
good grip on the problem, much preferable to fighting it out with a core
dump, and for the experienced and professional logs are Really Nice To
Have, and core dumps can be easily arranged when reproducing the error.
A: Because it messes up the order in which people normally read text.
Q: Why is it such a bad thing?
Q: What is the most annoying thing on usenet and in e-mail?
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]