Some errors in MIT's intro C++ course

  • Thread starter Alf P. Steinbach /Usenet
  • Start date
J

James Kanze

Oh my, the nonsense people pull from thin air. On multiple occasions
I've had to convert Perl to C++ and the C++ has /never/ been more than
3x the lines. The range is 1x to 3x. Your 40x claim is nearly comical
(and would be but for the poor noobs that will believe your nonsense).

It depends on what you're comparing (and when). A one liner in
perl may easily require thousands of lines in C++03, since you'd
have to implement regular expressions. (On the other hand,
I recently converted two small perl programs to C++ functions.
The C++ functions probably contained about twice the number of
lines, but they did more error checking, etc. And used
boost::regex, whose lines I didn't count.

If you have the appropriate library in one language (and there
aer a lot of ready built perl libraries, easy to find), and you
don't have it in the other language, then 10x/40x difference can
easily occur. I often find more than that between bash and C++,
because when I write bash, I'm really chaining together a lot of
diverse tools (libraries), which I'd often have to at least
partially implement in C++. (OK, I could use "system". But
that's not really in the spirit of C++.)
 
P

Pascal Bourguignon

James Kanze said:
Perl is probably the worst language I've ever seen. But it does
have a large number of ready-made modules which can simplify
a lot of tasks. (So do C++ and Java, for that matter. But
their generally a lot more difficult to find.)

Let's just write a googol-huge amount of libraries in Intercal so that
all these C++/Java/Perl programmers may switch to that language!

(And I would preconize also an Intercal to Brainfuck compiler, so that
they could write once and deploy everywhere on Brainfuck VMs).
 
J

Juha Nieminen

In comp.lang.c++ Jorgen Grahn said:
I have never, ever used a bounds-checking std::vector<T>::eek:perator[].
And I have never seen others use it, either. I rely on it to be as
fast as C array indexing.

I don't think you understand. operator[] will have bound-checking when
compiling in *debug* mode (with VC++ and some other compilers), not when
compiling in *release* mode.

Even with gcc you can turn bounds checks and other sanity checks (for
STL containers and algorithms) by defining the _GLIBCXX_DEBUG precompiler
macro when compiling. I have used it, and it has been very useful catching
silly mistakes very fast (which would have otherwise been very hard to
find).
 
J

Juha Nieminen

In comp.lang.c++ James Kanze said:
The "undefined behavior" should be a program crash on any
good implementation (at least one used by beginners). It is
with VC++ and with g++ (at least when invoked correctly).

No. It is in VC++ when compiling in debug mode, and in g++ only if
you define an obscure preprocessor macro (namely _GLIBCXX_DEBUG).

When compiling normally with optimizations, you most probably won't
get a crash, but erratic behavior.

(And even if you *are* compiling in debug mode, you are still not
*guaranteed* to get a crash because the standard says so. Unless Microsoft
and the gcc team have *promised* that it will crash now and in the future
for eternity, you have no guarantee.)
 
J

Jorgen Grahn

In comp.lang.c++ Jorgen Grahn said:
I have never, ever used a bounds-checking std::vector<T>::eek:perator[].
And I have never seen others use it, either. I rely on it to be as
fast as C array indexing.

I don't think you understand. operator[] will have bound-checking when
compiling in *debug* mode (with VC++ and some other compilers), not when
compiling in *release* mode.

Quoted out of context it may seem as if I don't understand, but I
believe I do. I was responding to this:

and my observation was simply that I have never seen that being done
in real life.

/Jorgen
 
D

Daniel

Most of the larger Java projects
I've seen have been, in fact, GUI front ends to other tools
(e.g. Eclipse).  Java is very good for GUI's, not because of the
language, but because of its libraries.
On the contrary, Java has had very little success on the GUI side.
Eclipse may be an exception, but it deliberately eschewed the standard
Java Swing components, and went its own way. Personally, I don't
particularly care for it as a development tool, it's very heavy, but
its success is largely attributable to its ability to front a huge and
diverse collection of enterprise tooling, much of it written in Java.

Which brings us to the area where Java has thrived over the last
decade, on the server side: enterprise middleware, high end workflow
products, business orchestration tooling, fault tolerant middleware,
messaging infrastructure, etc. The vast majority of the new tooling
in this space, from TIBCO, IBM, BEA and SUN (since absorbed by
Oracle), as well as new entrants, has been written in Java, and the
new products have been displacing the previous generation of tooling
that was written in C/C++.
Depending on what you're targetting, Java's distribution model
(with one jar file for all platforms) may be an advantage or
a disadvantage (the "write once, debug everywhere" syndrome).

Whether you choose Java, C# or C++
for such projects depends on a lot of issues: Java is clearly
the least powerful langauge of the three, but distribution
issues may make it preferrable.

I think the vendors of enterprise middleware would not agree with your
assessment. The movement from C/C++ to Java was motivated largely by
convenience, the convenience of using a language that offered
reasonable support for character encoding standards, that offered
support for calendars and dates, that supported threading and garbage
collection, that offered reflection and with it made configuration
easy, that didn't suffer from the security holes opened up by off-by-
one errors, that offered a simpler programming model, that was well
supported on UNIX. Of course, ease of deployment and distribution
were part of it.
A lot of the open source projects seem to be open source just to
show off how poorly they are engineered:).

You mean the boost libraries :) Seriously, I've only looked at a
small subset of these libraries, but my experience is bad.
Constructing an inverse t distribution doesn't work, the results of

const boost::math::students_t dist(dof);
const double t = boost::math::quantile(dist, y);

are pathological. banded_matrix doesn't work, multiplications go away
forever as the dimensions go up. This wouldn't be quite so irritating
if there weren't all those comments on the web about how boost was
developed by the best programmers in the world, people who are really
good don't need that. In numerics, you have to test everything, you
can't release code that doesn't work. Anyway, I agree, there is bad
free software.
Historical reasons also lead to e.g. using your own string class.)

In the case of Apache Xerces, I believe the introduction of XMLCh was
recent, motivated by the lack of standardization of wchar_t and the
need to support 16 bit wide unicode encodings. Anyway, you'll see
lots of use of

XMLString::transcode(elementName)

in XML application code.

-- Daniel
 
I

Ian Collins

I think the vendors of enterprise middleware would not agree with your
assessment. The movement from C/C++ to Java was motivated largely by
convenience, the convenience of using a language that offered
reasonable support for character encoding standards, that offered
support for calendars and dates, that supported threading and garbage
collection, that offered reflection and with it made configuration
easy, that didn't suffer from the security holes opened up by off-by-
one errors, that offered a simpler programming model, that was well
supported on UNIX. Of course, ease of deployment and distribution
were part of it.

Don't forget the biggest convenience of all: programmer availability!

When one of my favourite tool sets degraded to Java (and I do mean
degraded, it's memory footprint grew from about 50 to over 700MB!) I
asked the developers why and they told me they simply couldn't get
enough skilled C++/Motif programmers where Java programmers where two a
penny.
 
J

James Kanze

On Sep 16, 4:51 am, James Kanze <[email protected]>
wrote:> On Sep 12, 3:48 pm, Daniel <[email protected]>
wrote:
On the contrary, Java has had very little success on the GUI
side. Eclipse may be an exception, but it deliberately
eschewed the standard Java Swing components, and went its own
way. Personally, I don't particularly care for it as a
development tool, it's very heavy,

It's an IDE, which attempts to encompass everything. Visual
Studios is written in C++, and it's also very heavy:).
but its success is largely attributable to its ability to
front a huge and diverse collection of enterprise tooling,
much of it written in Java.
Which brings us to the area where Java has thrived over the last
decade, on the server side: enterprise middleware, high end workflow
products, business orchestration tooling, fault tolerant middleware,
messaging infrastructure, etc.

Java is very successful in contexts where plugins are wanted.
The kernel code will be written in C or C++, but will provide a
JVM, so user defined classes can be loaded. In this context,
the Java distribution model does have significant advantages: a
plugin written for one system will (presumably) work on another,
and the JVM provides a sandbox so that the plugin cannot
(presumably) corrupt the main application.
The vast majority of the new tooling
in this space, from TIBCO, IBM, BEA and SUN (since absorbed by
Oracle), as well as new entrants, has been written in Java, and the
new products have been displacing the previous generation of tooling
that was written in C/C++.

I'm not sure how much of the actual root products is written in
Java. But they do provide a Java interface for plugins. And
they tend to use Java a lot for auxiliary functionality, since
these are generally implemented as plugins as well.
I think the vendors of enterprise middleware would not agree with your
assessment.

Not if they're trying to sell their customers Java
interfaces:).
The movement from C/C++ to Java was motivated largely by
convenience, the convenience of using a language that offered
reasonable support for character encoding standards, that offered
support for calendars and dates, that supported threading and garbage
collection, that offered reflection and with it made configuration
easy, that didn't suffer from the security holes opened up by off-by-
one errors, that offered a simpler programming model, that was well
supported on UNIX.

That was Sun's original argument. Experience has shown that it
isn't totally valid. Or rather, that while Java did bring in a
number of new advantages, it threw out much of the essential.
Of course, ease of deployment and distribution were part of
it.

That, and the libraries, are the big reasons Java is used
today. With regards to the other points:

-- Threading may have been missing in the C++ standard, but
there are a lot of multi-threaded applications written in
C++ anyway. In practice, it's just as present in C++ as in
Java.

-- Garbage collection is an issue. Theoretically, it's
available as a third party plugin in C++, but it's not that
much used. Of course, if you're using value semantics (as
C++ does), it's less of an issue than for Java, but it would
still be nice (and it's absense does create serious security
issues).

-- Reflection is nice for debuggers and such (and some types of
plugins), but is not generally very useful. I've rarely
seen it used in actual Java applications, or if so, only in
very trivial ways that can easily be emulated (more safely,
in fact) in C++.

-- Off by one errors are a serious problem where C interfaces
are involved, but in pure C++, you just use one of the
mainstream standard libraries (Dinkumware or g++), and you
have bounds checking.
You mean the boost libraries :)

Some of them, maybe, but on the whole, they are well engineered
with regards to the goals they set. (Whether those goals are
appropriate for your project is another issue.)

But I was thinking more of the tons of projects you see by one
or two people.
Seriously, I've only looked at a
small subset of these libraries, but my experience is bad.
Constructing an inverse t distribution doesn't work, the results of
const boost::math::students_t dist(dof);
const double t = boost::math::quantile(dist, y);
are pathological. banded_matrix doesn't work, multiplications go away
forever as the dimensions go up. This wouldn't be quite so irritating
if there weren't all those comments on the web about how boost was
developed by the best programmers in the world, people who are really
good don't need that.

It depends on the library. Some are better than others, and
some are not particularly good. (I'm not familiar with the math
library, so I can't comment here.)
In numerics, you have to test everything, you can't release
code that doesn't work.

In numerics, testing isn't sufficient. You have to analyse the
program logic manually to ensure numeric stability. (That
doesn't mean you shouldn't test, but that you need more than
just testing.)
 
J

James Kanze

On 09/18/10 03:49 PM, Daniel wrote:

[...]
Don't forget the biggest convenience of all: programmer availability!
When one of my favourite tool sets degraded to Java (and I do mean
degraded, it's memory footprint grew from about 50 to over 700MB!) I
asked the developers why and they told me they simply couldn't get
enough skilled C++/Motif programmers where Java programmers where two a
penny.

That's an interesting point, to which I'm not sure I agree,
although I can see where a manager might think so. C++ is
clearly a more complicated language than Java. But some of that
complexity is there to allow it to solve more complex problems.
A programmer capable of solving such problems is capable of
learning C++ well. Less competent programmers have real
problems with C++. (I'm not talking of some of the critics in
this thread. They obviously are capable C++ programmers as
well, even if for some reason, they prefer Java.) Since
learning C++ well requires real skill, there are less C++
programmers, but the Java programmers who aren't capable of
learning C++ probably aren't capable of writing good code in
Java either (although they may know Java the language well).

In some cases, this isn't a problem. In the applications I've
worked on, Java has generally been relegated to the less
critical parts, and to parts with much smaller and simpler to
understand modules, so the programmer qualification doesn't have
to be as high (independently of the language). Java's actually
a fairly good choice for these elements, because C++ does
require more skill, even when the application itself doesn't.
 
I

Ian Collins

On 09/18/10 03:49 PM, Daniel wrote:
[...]
Don't forget the biggest convenience of all: programmer availability!
When one of my favourite tool sets degraded to Java (and I do mean
degraded, it's memory footprint grew from about 50 to over 700MB!) I
asked the developers why and they told me they simply couldn't get
enough skilled C++/Motif programmers where Java programmers where two a
penny.

That's an interesting point, to which I'm not sure I agree,
although I can see where a manager might think so. C++ is
clearly a more complicated language than Java. But some of that
complexity is there to allow it to solve more complex problems.
A programmer capable of solving such problems is capable of
learning C++ well. Less competent programmers have real
problems with C++. (I'm not talking of some of the critics in
this thread. They obviously are capable C++ programmers as
well, even if for some reason, they prefer Java.) Since
learning C++ well requires real skill, there are less C++
programmers, but the Java programmers who aren't capable of
learning C++ probably aren't capable of writing good code in
Java either (although they may know Java the language well).

Reading between the lines I think the true picture was more like "we can
get several cheap java programmers for every expensive C++/Motif one"...
I think Motif was more of an issue than C++.
 
J

James Kanze

Jorgen Grahn ha scritto:
But that's what I said right from the beginning: I'd tell
them that formally you cannot count on operator[] detecting
an error, but in the context of the course and with a
quality implementation used with correct compiler settings
it will work as expected,
I don't see how that helps the students. If they want such
detection, they can run their programs under valgrind or
Purify (which they should be taught to do anyway, to catch a
dozen other common newbie errors).
I don't understand... actually, this was just about operator[]
vs. at(), and in both cases, the resulting crash won't
automatically point students to the wrong line of code, if
that's what you mean.

But the stack trace from the core dump will contain the wrong
line of code. Where as with an uncaught exception, it might not
The crash first of foremost helps students in that they
immediately see that their code is wrong and must be fixed.

And it can't be caught:). Which is an advantage where students
are involved.
and it is also the commonly preferred form in "real" code,
not only in exercises at university.
I have never, ever used a bounds-checking
std::vector<T>::eek:perator[]. And I have never seen others
use it, either. I rely on it to be as fast as C array
indexing.
I meant "preferred form" in the sense that it is preferred
over at().

If the profiler says that you can't afford bounds checking (and
on most systems, it can only be turned on or off globally, with
a lot of other, far more expensive tests), then you can't afford
it, and you have to turn it off. In that case, however, you
generally can't use at() either.

There is a real issue that these checks must be turned on or off
globally, for the entire program. Which means that one critical
loop, and you're without bounds checking everywhere.
This is indeed a rumor.
#include <vector>
int main()
{
std::vector<int> v;
v.reserve(100);
v[0] = 1;
}
If you compile this just with "cl test.cpp", then you probably
won't get a crash.

But if you use the IDE, with the default settings, you probably
will. (I don't have any compilers installed on my machne here,
so I can't check.)

Note that if you compile with /MDd, and don't have bounds
checking turned on, you'll get some occasional problems
(crashes, etc.) with std::string (pre-VS 2010, at least---I've
been told by people at Microsoft that this problem has been
fixed in VS 2010). And in practice, you do have to specify
either /MDd or /MD is you want your code to work with user
written DLLs.
 
J

James Kanze

No. It is in VC++ when compiling in debug mode, and in g++
only if you define an obscure preprocessor macro (namely
_GLIBCXX_DEBUG).

In other words, it is the behavior when the compiler is invoked
correctly. Exactly what I said. (I'm not sure what you mean by
"debug" mode with VC++. VC++ doesn't have a "debug" mode, and I
don't know what VC++ does by default. The IDE does have a debug
mode, which is what it defaults to.)
When compiling normally with optimizations, you most probably
won't get a crash, but erratic behavior.

You choose the options you compile with. If the profiler says
you can't afford bounds checking, then you turn it off. But if
you can't afford bounds checking, then you can't use at().
(And even if you *are* compiling in debug mode, you are still
not *guaranteed* to get a crash because the standard says so.
Unless Microsoft and the gcc team have *promised* that it will
crash now and in the future for eternity, you have no
guarantee.)

You are compiling with a specific compiler. Always. Both
Microsoft and g++ have documented the meaning of the various
command line options. You're using a documented feature.
Beyond that, it's a question of QoI, and how much the vendor
cares about his customers. But that's always the case. (You
can imagine the opposite as well. You have a time critical
application which requires bounds checking to be turned off in
order to run in an acceptable time. What guarantees you that
the next release will have the option of turning it off?)
 
J

James Kanze

In comp.lang.c++ Jorgen Grahn said:
I have never, ever used a bounds-checking std::vector<T>::eek:perator[].
And I have never seen others use it, either. I rely on it to be as
fast as C array indexing.
I don't think you understand. operator[] will have
bound-checking when compiling in *debug* mode (with VC++ and
some other compilers), not when compiling in *release* mode.
Quoted out of context it may seem as if I don't understand, but I
believe I do. I was responding to this:
and my observation was simply that I have never seen that
being done in real life.

:)

Put that way...

There may be some disagreement as to what is meant by "in real
life", or "commonly prefered". We all know that there's an
awful lot of bad code being written, and that a lot of
programmers are too concerned about performance when it is not
an issue. (The same programmers, by the way, tend to write very
poorly performing programs when performance is an issue.) So
the issue is whether we're talking about the real life over the
set of all programmers, or only over the set of competent
programmers working in well managed environments. Competent C++
programmers commonly prefer leaving bounds checking in when
delivering their product. (If they can afford the runtime
overhead.)
 
K

Kai-Uwe Bux

James said:
In other words, it is the behavior when the compiler is invoked
correctly. Exactly what I said.

[...]

Exactly which definition of "invoked correctly" are you using?


Best

Kai-Uwe Bux
 
D

Daniel

I'm not sure how much of the actual root products is written in
Java.  

I think that's pretty obvious :) You could do something about that,
though. Maybe ask somebody who works in the space. Jeez.

-- Daniel
 
J

Jorgen Grahn

On 09/18/10 03:49 PM, Daniel wrote: ....

Don't forget the biggest convenience of all: programmer availability!

When one of my favourite tool sets degraded to Java (and I do mean
degraded, it's memory footprint grew from about 50 to over 700MB!) I
asked the developers why and they told me they simply couldn't get
enough skilled C++/Motif programmers where Java programmers where two a
penny.

I think Motif is the key word there. It sounds like software from the
early 1990s, written in C++ of the early 1990s, with the style ("best
practice") people had back then. I wouldn't be surprised if the Java
rewrite was caused by the complete deterioration of the current
codebase, programmers leaving in disgust, etc.

Of course I don't know the tool in question.

/Jorgen
 
J

Jorgen Grahn

On 09/18/10 03:49 PM, Daniel wrote:
[...]
Don't forget the biggest convenience of all: programmer availability!
When one of my favourite tool sets degraded to Java (and I do mean
degraded, it's memory footprint grew from about 50 to over 700MB!) I
asked the developers why and they told me they simply couldn't get
enough skilled C++/Motif programmers where Java programmers where two a
penny.

That's an interesting point, to which I'm not sure I agree,
although I can see where a manager might think so. C++ is
clearly a more complicated language than Java.

Is that so clear in practice? I don't use Java myself, but I'm on the
company Java mailing list. There seems to be a huge set of APIs,
frameworks and abbreviations you have to know, and there seems to be
plenty of fashions you have to follow (e.g. FOO-driven development,
where FOO changes quarterly).

Of course, from the outside it may seem as if you need to do virtual
inheritance or template metaprogramming to be a real C++ programmer --
so maybe that's just my outsider view of Java.

/Jorgen
 
J

Jorgen Grahn

Ok. I'll try to use less pejorative terms. I didn't realize that
people would take it as some sort of attack on C++. (I still stand by
my words as an apt characterization, though if it fails to get my
intended message across due to perceived implied intent, then yes, I
should choose different words.) I do like C++, and prefer it to Java
generally. However, I recognize its weaknesses, such as the near
entire lack of effective fault isolation intra-process.

Thanks. Perhaps my paranoia is the problem rather than your phrasing
.... but this is Usenet -- half the population is paranoid. And the
other half is trying to hurt us :)

/Jorgen
 
P

Pavel

James said:
I have never, ever used a bounds-checking std::vector<T>::eek:perator[].
And I have never seen others use it, either. I rely on it to be as
fast as C array indexing.
I don't think you understand. operator[] will have
bound-checking when compiling in *debug* mode (with VC++ and
some other compilers), not when compiling in *release* mode.
Quoted out of context it may seem as if I don't understand, but I
believe I do. I was responding to this:
and my observation was simply that I have never seen that
being done in real life.

:)

Put that way...

There may be some disagreement as to what is meant by "in real
life", or "commonly prefered". We all know that there's an
awful lot of bad code being written, and that a lot of
programmers are too concerned about performance when it is not
an issue. (The same programmers, by the way, tend to write very
poorly performing programs when performance is an issue.) So
the issue is whether we're talking about the real life over the
set of all programmers, or only over the set of competent
programmers working in well managed environments. Competent C++
programmers commonly prefer leaving bounds checking in when
delivering their product. (If they can afford the runtime
overhead.)
Library writers usually can't afford it. They rarely have certainty that
the performance of a particular API will never be critical for any
client code. Thus, in library code you usually use the fastest (that is,
unsafe) API, check correctness explicitly (e.g. with asserts or more
often with library- or company- specific analogue) wherever necessary
and deliver both a debug version with the checks preprocessed-in and a
production version with the checks preprocessed-out. If you plan to only
support VC you could take advantage of its bound-checking [] for the
debug version but in these days of no MS monopoly it's probably wiser to
invest little more keystrokes and type the checks in explicitly.

Just my 2c
-Pavel
 
P

Pavel

James said:
On Sep 10, 3:56 pm, (e-mail address removed) (Pascal J. Bourguignon)
wrote:
James Kanze ha scritto:
[...]
So, you have to teach:
To make an array you write: std::vector<element_type> v(size);
To access to the vector you write: v.at(index)
Why the at? That's an advanced feature, for the special
(and rare) cases where you want an exception on a bounds
error, instead of a crash.
#include<vector>

int main)
{
std::vector<int> v(100U, 0);
v[100] = v[-1];
}
compiled without complaint ... didnt crash .. Great!
Program must be working .. ;-)

It crashes with all of the compilers I use.
He just gave a too broken example. Much more common UB code in a
beginner's program would be something like v[100] = -1; and that
probably would not crash with at least some of your compilers, would it?

-Pavel
 

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,535
Members
45,007
Latest member
obedient dusk

Latest Threads

Top