Some errors in MIT's intro C++ course

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

Alf P. Steinbach /Usenet

[This article is cross-posted to comp.lang.c++ and comp.programming]

I was a bit shocked when I saw this a few days ago. I then used the MIT Open
Courseware feedback option to inform them of the problems, where I explained
things at about the same detail level as below, and was told that if a response
was required it would be given within two business days. Well, either there's a
holiday on in the MIT area, or MIT doesn't think this is problematic.

This is a very short intro course, covering only basics, so the error frequency
is quite high.


Dunietz, Jesse, Radhika Malik, and Tanmay Kumar, 6.096 Introduction to C ,
January IAP 2009. (Massachusetts Institute of Technology: MIT OpenCourseWare),
http://ocw.mit.edu (Accessed 08 Sep, 2010). License: Creative Commons BY-NC-SA

http://ocw.mit.edu/courses/electric...nce/6-096-introduction-to-c-january-iap-2009/

6.096 Introduction to C++
As taught in: January IAP 2009

Level:
Undergraduate / Graduate

Course Description
This course is designed for undergraduate and graduate students in science,
social science and engineering programs who need to learn fundamental
programming skills quickly but not in great depth. The course is ideal for
undergraduate research positions or summer jobs requiring C++. It is not a class
for experienced programmers in C++. Students with no programming background are
welcome. Topics include control structures, arrays, functions, classes, objects,
file handling, and simple algorithms for common tasks.
This course is offered during the Independent Activities Period (IAP), which is
a special 4-week term at MIT that runs from the first week of January until the
end of the month.



*** Lecture 1 "Basics"

Page 1/6 "Header files"

INCORRECT. <iostream.h> is not a standard C++ header.
The corresponding standard C++ header is <iostream>.

Page 1/16 "Unary and binary operators"

INCORRECT. "To nullify a variable, you can write the exclamation point to its
left" is meaningless.
!a is a value operation, not an operation on a variable. It does not nullify (in
the ordinary meaning of that word), it produces the logical negation of a
boolean value. The latter is possibly just a terminological issue, but very
misleading.

Page 1/18 "Data types in C++"

MISLEADING. The "Range" column lists ranges of various data types with a Windows
C++ compiler, without stating that it's a Windows C++ compiler, and no context
implying that. In standard C++ these are not guaranteed minimum ranges. Nor are
they maximum ranges.

Page 1/19 "Data types in C++"
INCORRECT. type bool is said to have size "1 bit". The minimum size in C++ is 1
byte. Anyway, it's meaningless.

Page 1/20 "Variable declaration and naming conventions"
WPFU. Word processing foul-up: `a´ is not valid C++ syntax. 'a' is valid.
EVIL. Teaching evil practice: "Constants are all in uppercase". Every good C++
FAQ, including Bjarne Stroustrup's own, and every good C++ textbook, tells you
that in C++ all uppercase should be reserved for macros. All uppercase constants
are a Java/Python/etc. convention (where it can do some good), not a C++
convention (where it causes needless name collisions).

Page 1/22 "Starting to write programs"
WPFU. Word processing foul-up. The double-quote characters used are not
representable in Latin-1 so I can't quote it here, but it's not valid C++. Valid
C++ would be e.g. "Hello".


*** Lecture 3 "Functions"

Page 3/2 "char vs. char*"

INCORRECT. The second paragraph's first statement, "A char *, or a string,
stores a series of 0 or more characters", is incorrect. char* is a pointer to char.

INCORRECT. The second paragraph's second statement, "A constant char * value is
indicated with "double quotes"", is incorrect. A string literal denotes an array
of characters. An array is not a pointer (this confusion is repeated in a later
lecture).

Page 3/7

INCORRECT. The statement "Trying to change the value of number in the body of
square would be a syntax error" is incorrect. It would be an error, yes, but it
would not be a syntax error.


*** Lecture 4 "Arrays"

Page 4/6 "Initializing arrays"

WPFU. Word-processing foul-up of quote marks.

Page 4/11 "Linear search in arrays"
Page 4/16 "Binary search code snippet"

WPFU. Word processing foul-up of indentation (not really an error but ungood).
EVIL. Teaching evil practices (uppercase single letter names, comparing bool to
true/false, so on).


*** Lecture 5 "Pointers"

Page 5/4 "Pointers and arrays"

INCORRECT. "The name of an array is in fact just a pointer to the first element
in the array". It is not (e.g. sizeof(a), or passing an array by reference).
INCORRECT. "Passing an array is really passing a pointer". In C++ arrays can be
passed by reference.

Page 5/5 "Null, uninitialized, and deallocated pointers"

DEBATABLE. "... a null pointer ... is an invalid pointer". Neither C++98 nor
C++0x defines "invalid pointer", but the common terminology is to not regard a
nullpointer as an invalid pointer. Instead that term is reserved for pointers
where rvalue conversion of the pointer, causes UB.

INCORRECT. "Any attempt to dereference it will result in a runtime error".
First, a nullpointer can be safely dereferenced in a typeid expression. Second,
C++ does not define the result of dereferencing nullpointers in other contexts,
it's Undefined Behavior. Third, C++ has no notion of runtime error (it's just
one possible effect of UB).

Page 5/5 "char * and char[]"

INCORRECT. "Arrays of chars and pointers to char are interchangeable". No,
they're not, e.g. sizeof(a) or passing an array by reference.

INCORRECT. "[modifying a string constant] is either a syntax error or a runtime
error". No, it's not a syntax error.

Page 5/6

INCORRECT. "... you can declare a variable of type string (once you've included
the cstring standard header" .The header that declares the std::string type is
<string>. The header <cstring> is a different one.



*** Lecture 7 "Classes, part 2"

Page 7/3

INCORRECT. "[A constructor] initializes global variables". No, generally it does
not.

Page 7/6

INCORRECT. "A default constructor is a constructor that either has no
parameters, or if it has parameters, all the parameters have have default
values". The standard's definition is that a default constructor can be called
without arguments. E.g. 'T(...)' is a default constructor of class T.

Page 7/9

INCORRECT (FINE POINT). "If a copy constructor is not defined in a class, the
compiler itself defines one". In C++ there is a difference between "declared"
and "defined". "not defined" is incorrect (with practically significant
consequence) and should be replaced with "not declared".

Page 7/14

INCORRECT. "the assignment operator is not inherited". Assignment operators are
inherited, but are typically hidden by a programmer defined or automatically
generated derived class copy assignment operator.


*** Lecture 9 "File handling, operator overloading, and exceptions"

Page 9/2 "What does iostream.h contain?"

INCORRECT, 3 TIMES. <iostream.h> is not a standard C++ header. The corresponding
C++ header is <iostream>.

Page 9/5 and 9/6 "Function eof()-end of file"

CONFUSED. The example at the end is described both as a solution to a problem
(it's not), and as producing extraneous output (which it does).


*** Problem set 1 solutions

Page PS1/4 problem 9

EVIL "const int NUMBER_OF_VARIABLES = 2;" Reserve uppercase names for macros.

INCORRECT. "++x %= NUMBER_OF_VARIABLES" variable modified twice between sequence
points, Undefined Behavior.


*** Problem set 6 solutions

Page PS6/2 problem 1a
Page PS6/2 problem 1b

INCORRECT. The header <ctime> does not guaranteed declare time_t in the global
namespace. Should be std::time_t, or alternatively <time.h>.

EVIL. "getTime" for a member functin is a Java-ism.

Page PS6/7 problem 6

INCORRECT. The solution class Array fails to meet the "rule of three" by not
declaring an assignment operator, and will cause Undefined Behavior if Array
objects are ever assigned (due to double deletion).


*** Problem set 7 solutions

Page PS7/2 lab 7

INCORRECT. <conio.h> is not a standard C++ header.



Cheers,

- Alf (shocked)
 
R

red floyd

[This article is cross-posted to comp.lang.c++ and comp.programming]

I was a bit shocked when I saw this a few days ago. I then used the MIT Open
Courseware feedback option to inform them of the problems, where I explained
things at about the same detail level as below, and was told that if a response
was required it would be given within two business days. Well, either there's a
holiday on in the MIT area, or MIT doesn't think this is problematic.

Just an FYI, Alf, not related to any of your comments (which seem
quite accurate to me):

Monday, 6 September, was a holiday (Labor Day) in the US. Don't know
if that helps with your timeline or not.
 
G

Goran Pusic

Cheers,
- Alf (shocked)

Hmmm... Not good, but I don't know about the "shocked" part.

The thing is, even though we're talking about fine academia (MIT _is_
considered a fine academia, right?), it's an introductory course in
the matter of practical programming (or so I guess), so precision is
kinda overrated. Even if course material was of a much higher quality,
students at this stage won't be able to neither appreciate or
understand finer points anyhow.

Also, if the course is actually there to teach students both C and C++
(which it seems to do)... Well, that doesn't help. It's just that the
material is enormous.

But hopefully if your post will help push MIT and other schools to
produce better material.

Education is not easy ( says a guy who escaped working in it ;-) ).

Goran.
 
Z

Zeljko Vrba

The thing is, even though we're talking about fine academia (MIT _is_
considered a fine academia, right?), it's an introductory course in
the matter of practical programming (or so I guess), so precision is
kinda overrated. Even if course material was of a much higher quality,
students at this stage won't be able to neither appreciate or
understand finer points anyhow.
Well, programming *is* very much about precision, i.e., precisely expressing
algorithmic ideas in a non-natural language (C++ in this case). If students
don't get that drilled into their subconciousness in an introductory course,
WHEN will they?

I agree that some percentage of students wouldn't be able to understand some of
the finer points. BUT, such materials send an implicit message that sloppyness
and/or cluelesness is "OK", which is not a good way of approaching programming.
Computers forgive neither.

(Even students less-knowledgeable in the start will eventually find out about
the mistakes through google or sites such as stackoverflow.)
 
A

Alf P. Steinbach /Usenet

* Alf P. Steinbach /Usenet, on 08.09.2010 21:15:
http://ocw.mit.edu/courses/electric...nce/6-096-introduction-to-c-january-iap-2009/


6.096 Introduction to C++
As taught in: January IAP 2009

Level:
Undergraduate / Graduate

Course Description
This course is designed for undergraduate and graduate students in science,
social science and engineering programs who need to learn fundamental
programming skills quickly but not in great depth.

[snip list of errors]

I'm happy to report that the MIT course ...

[
http://ocw.mit.edu/courses/electric...object-oriented-programming-january-iap-2010/

6.088 Introduction to C Memory Management and C++ Object-Oriented Programming
As taught in: January IAP 2010

Level:
Undergraduate
]

.... appears to have far fewer errors.

In the first three lectures, covering basic C and memory management, a cursory
reading revealed no obvious technical errors. However, MIT's conversion to PDF
had removed some critical characters and lines in the code. E.g., "int* p, q;"
instead of "int *p, *q;" to declare two pointers (or, it may have been a lack of
understanding of the C syntax, but given the rest, and given a later white area
in the code I think it must have been the conversion to PDF that did it).

In the three remaining lectures, covering basic OO in C++, I saw only 1 obvious
source code error, declaring an initialized static member of 'float' type. This
was corrected in a later code sample so it seems the lecturer was discovering
the rules, writing the slides first and then actual code. Another hint in that
direction: the term "override" is incorrectly used to mean "redefine" in derived
class, and the lecturer went on about this (incorrect meaning of "override") for
several slides, so, not quite acquainted with C++.

For a course aimed at teaching memory management /and/ C++ OO, it would have
been nice if the student was shown how to use object oriented C++ memory
management, i.e. standard library containers and smart pointers.

Alas, instead also the C++ part (the three last lectures) is based on using raw
pointers and raw arrays, mentioning the standard library only at the very end.


Cheers,

- Alf (newfound calling, to evaluate MIT C++ courses :) )
 
J

Joshua Maurice

Alas, instead also the C++ part (the three last lectures) is based on using raw
pointers and raw arrays, mentioning the standard library only at the very end.

In MIT's defense, I think this is the way it should be. A good
programmer needs to understand the basics, and that includes raw
arrays. Only once one understands how to implement something simple
like vector should he actually use vector over raw arrays.

However, once he understands fully, hopefully he'll never use a raw
array again. (Wishful thinking.)
 
J

James Kanze

In MIT's defense, I think this is the way it should be. A good
programmer needs to understand the basics, and that includes raw
arrays. Only once one understands how to implement something simple
like vector should he actually use vector over raw arrays.
However, once he understands fully, hopefully he'll never use a raw
array again. (Wishful thinking.)

NO! A beginning programmer, learning a language, has to, first
and foremost, understand the basic idioms of the language. In
C++, "raw" arrays are for special, advanced uses; the basic
idiom is std::vector, and that's what a beginning programmer
should learn first. (An experienced C++ will, of course, use
raw arrays as well as std::vector, depending on his needs.)
 
A

Alf P. Steinbach /Usenet

* Paul N, on 10.09.2010 13:34:
On 9 Sep, 21:17, "Alf P. Steinbach /Usenet"<alf.p.steinbach
(e-mail address removed)> wrote:

(snip)


I thought that the term "override" meant that a function in a derived
class replaced a virtual function in the base class. This is what FAQ
20.1 seems to define it as. It also seems to be what you are saying
the course defines it as, and checking from the slides it does indeed
seem to be what the course defines it as. Could you clarify the
difference between what you think the course says and what you think
to be correct?

Hi Paul.

First, it's not a matter of personal opinion, as it seems you think.

C++ has an international standard, ISO/IEC 14882, that defines these things.

Essentially (I'm not sure how much of "virtual" you know about), when a class
Derived /overrides/ a method m from class Base, and you have a pointer p of type
Base* that points to an object originally created as Derived, then writing
p->m() invokes D::m.

That does not happen for a non-virtual method. When m is non-virtual the
expression p->m() invokes Base::m, because the known static type is Base. In
this case a/the redefinition of m in Derived is not an override.

The term "override" is loosely defined by the C++98 standard's §10.3/2, and then
used in many places in the standard to make the distinction I explained above.
"Override" applies only to virtual member functions. A non-virtual function can
be redefined in a derived class, and then the redefinition by default "hides"
the base class member.

For example, rules such as the standard's §10.3/5 about the return type of an
overriding function would be rather inconvenient, and meaningless, if "override"
refererred to non-virtual functions; it does not.

The MIT course, in contrast, incorrectly uses the word "override" about
non-virtual member functions (and goes on at length to define it that way),
which would make it impossible for a naïve student to understand parts of the
C++ standard such as the standard's §10.3/5, and corresponding concepts and
practical techniques such as C++ function result covariance.


Cheers & hth.,

- Alf
 
P

Pascal J. Bourguignon

Christian Hackl said:
James Kanze ha scritto:


Yes, exactly.

As I've said a few times before in this group, I was once personally
involved in a course which taught arrays/pointers first and the
standard containers as something very special.

It simply doesn't work, and it is also very frustrating for students;
once they finally manage to use dynamic arrays correctly in face of
copy constructors, assignment operators and exception safety in a
slightly more advanced program (which may well take an entire
semester, because after all this is not exactly easy stuff for a
beginner, and at university you usually have a lot of other courses,
not only one about C++), they cannot even take satisfaction in their
new abilities, because you have to tell them that all of this is
"evil" and that if they just write "std::vector<...>" they will get
rid of all their hand-made memory management code.

And of course, some will just stick to raw arrays because "they work"
and they "don't need special classes".


It's almost like teaching how to build your own virtual dispatch
device from scratch before introducing the virtual keyword... :)


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)


Then you may mention that there is a low-level, unsafe feature whose syntax is:

To make an array you write: element_type v[size];
To access to the vector you write: v[index]

which obviously is much more practical to write, but that you shouldn't use.


Doesn't this just demonstrate that the whole language should be canned?
 
L

lucdanton

Christian Hackl said:
James Kanze ha scritto:
Yes, exactly.
As I've said a few times before in this group, I was once personally
involved in a course which taught arrays/pointers first and the
standard containers as something very special.
It simply doesn't work, and it is also very frustrating for students;
once they finally manage to use dynamic arrays correctly in face of
copy constructors, assignment operators and exception safety in a
slightly more advanced program (which may well take an entire
semester, because after all this is not exactly easy stuff for a
beginner, and at university you usually have a lot of other courses,
not only one about C++), they cannot even take satisfaction in their
new abilities, because you have to tell them that all of this is
"evil" and that if they just write "std::vector<...>" they will get
rid of all their hand-made memory management code.
And of course, some will just stick to raw arrays because "they work"
and they "don't need special classes".
It's almost like teaching how to build your own virtual dispatch
device from scratch before introducing the virtual keyword... :)

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)

Then you may mention that there is a low-level, unsafe feature whose syntax is:

To make an array you write:         element_type v[size];
To access to the vector you write:  v[index]

which obviously is much more practical to write, but that you shouldn't use.

Doesn't this just demonstrate that the whole language should be canned?

std::vector is most equivalent to:

element_type *data = malloc(ELEMENT_COUNT * sizeof *data);
data[index];
free(data);

The most (IMO) equivalent to element_type data[ELEMENT_COUNT] is:

std::array<element_type, element_count> data;
data.at(index);

If it's C++03, there is std::tr1::array (which I hope does have a at
member).
If not, there is boost::array (or boost::tr1::array).
Or you can roll your own (IMO not a good exercise for an introductory
course however).
 
P

Paul N

* Paul N, on 10.09.2010 13:34:







Hi Paul.

First, it's not a matter of personal opinion, as it seems you think.

C++ has an international standard, ISO/IEC 14882, that defines these things.

Essentially (I'm not sure how much of "virtual" you know about), when a class
Derived /overrides/ a method m from class Base, and you have a pointer p of type
Base* that points to an object originally created as Derived, then writing
p->m() invokes D::m.

That does not happen for a non-virtual method. When m is non-virtual the
expression p->m() invokes Base::m, because the known static type is Base. In
this case a/the redefinition of m in Derived is not an override.

The term "override" is loosely defined by the C++98 standard's §10.3/2, and then
used in many places in the standard to make the distinction I explained above.
"Override" applies only to virtual member functions. A non-virtual function can
be redefined in a derived class, and then the redefinition by default "hides"
the base class member.

For example, rules such as the standard's §10.3/5 about the return type of an
overriding function would be rather inconvenient, and meaningless, if "override"
refererred to non-virtual functions; it does not.

The MIT course, in contrast, incorrectly uses the word "override" about
non-virtual member functions (and goes on at length to define it that way),
which would make it impossible for a naïve student to understand parts of the
C++ standard such as the standard's §10.3/5, and corresponding concepts and
practical techniques such as C++ function result covariance.

Thanks. Yes, I see your point now.

The course does first introduce a non-virtual function of the same
name and call this "overriding". It quite quickly starts explaining
how this can give unexpected results and shows how the cure is to make
the function virtual, but it fails to go back and say "actually we
were wrong to call this one overriding..."

Paul.
 
J

James Kanze

[...]
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.
Then you may mention that there is a low-level, unsafe feature
whose syntax is:
To make an array you write: element_type v[size];
To access to the vector you write: v[index]
which obviously is much more practical to write, but that you
shouldn't use.

Or should use when appropriate: it's not that C style arrays are
"low-level" (although they are), but that they have very
peculiar semantics.
Doesn't this just demonstrate that the whole language should
be canned?

Just because it's not perfect? C compatibility comes at
a price, but C++ probably wouldn't be anywhere near as widely
used without it.
 
P

Pascal J. Bourguignon

James Kanze said:
Christian Hackl said:
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.

LOL!

If you prefer a crash, why not use raw arrays and have out of bounds
crashes all the time?


Then you may mention that there is a low-level, unsafe feature
whose syntax is:
To make an array you write: element_type v[size];
To access to the vector you write: v[index]
which obviously is much more practical to write, but that you
shouldn't use.

Or should use when appropriate: it's not that C style arrays are
"low-level" (although they are), but that they have very
peculiar semantics.
Doesn't this just demonstrate that the whole language should
be canned?

Just because it's not perfect? C compatibility comes at
a price, but C++ probably wouldn't be anywhere near as widely
used without it.

And probably should be used much less than it is for it.
 
K

Kai-Uwe Bux

Pascal said:
James Kanze said:
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.

LOL!

If you prefer a crash, why not use raw arrays and have out of bounds
crashes all the time?

Of course, you use std::vector because with an array you are _less_ likely
to get a crash for out of bounds :)

Formally, you have undefined behavior in both cases (vector and array).
However, with operator[] in std::vector, as a matter of quality of
implementation, you are likely to see

assert( arg < size() );

or something like that. So, for good implementations of vector::eek:perator[]
you have a documented way to get a crash for out-of-bounds errors. With the
array, the compiler is less likely to generate bounds checking code.


As for operator[] vs at(): in cases where out-of-bounds errors are bugs, I
don't see what an exception buys you. Once you see that exception thrown,
you have to hunt down the bug and change the program anyway. Thus, during
the run of the program where the exception is thrown, you just discover that
the internal state of your program is inconsistent: different parts of the
program have different opinions on how long the vector is. The safest thing
would be to abort anyway before the inconsistency gets out of hand and your
program spends millions of dollars automatically buying stock options.


Best

Kai-Uwe Bux
 
J

Joshua Maurice

NO!  A beginning programmer, learning a language, has to, first
and foremost, understand the basic idioms of the language.  In
C++, "raw" arrays are for special, advanced uses; the basic
idiom is std::vector, and that's what a beginning programmer
should learn first.  (An experienced C++ will, of course, use
raw arrays as well as std::vector, depending on his needs.)

I humbly disagree. I would rather that students have a firm grasp of
the language basics before using canned containers. I believe that a
firm grounding in simple imperative programming, such as assembly or
preferably simple C, is essential to being a good programmer. I
believe that you can use the standard library "better" if you
understand how the standard library is implemented. I see this problem
too often with Java programmers who do not understand basic complexity
theory and how their containers and standard libraries are
implemented, and consequently write very bad code.
 
J

Juha Nieminen

In comp.lang.c++ James Kanze said:
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.

Since when has the safer variant been the "advanced feature", while the
variant which causes UB when misused is the one suitable for beginners?
 
K

Kai-Uwe Bux

Pascal said:
Kai-Uwe Bux said:
Pascal 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.

LOL!

If you prefer a crash, why not use raw arrays and have out of bounds
crashes all the time?

Of course, you use std::vector because with an array you are _less_
likely to get a crash for out of bounds :)

Formally, you have undefined behavior in both cases (vector and array).
However, with operator[] in std::vector, as a matter of quality of
implementation, you are likely to see

assert( arg < size() );

or something like that. So, for good implementations of
vector::eek:perator[] you have a documented way to get a crash for
out-of-bounds errors. With the array, the compiler is less likely to
generate bounds checking code.


As for operator[] vs at(): in cases where out-of-bounds errors are bugs,
I don't see what an exception buys you. Once you see that exception
thrown, you have to hunt down the bug and change the program anyway.
Thus, during the run of the program where the exception is thrown, you
just discover that the internal state of your program is inconsistent:
different parts of the program have different opinions on how long the
vector is. The safest thing would be to abort anyway before the
inconsistency gets out of hand and your program spends millions of
dollars automatically buying stock options.

In some circumstances, you just cannot stop the program and wait for
programmers to correct the bug. Think about robots, or space probes.
Then you want to be able to catch the exceptions, and if you can reset
the vector to a bigger one and try again, or if you can just restart
the procedure and hopefully, real-time circumstances having changed,
avoid the bug, it would be much better than crashing a rocket or
hitting your grandma.

True, it depends on the circumstances: in a game, the player experience is
severely bad when it crashes, but a few frames where the physics is a little
off do not matter that much. On the other hand, I'd rather have a compiler
crash with "internal compiler error" than completing the run and producing
bogus code (which then will send me on a goose chase as I'd be hunting bugs
in _my_ code that are just figments of imagination).


Best

Kai-Uwe Bux
 
J

Joshua Maurice

Dynamic allocation and deallocation (the perrils of using pointers) are by
no means the _basics_ of C++.

I think they're more basic than std::vector in terms of "first
principles". std::vector is implemented in terms of dynamic memory
allocation and deallocation, not the other way around. However, this
is rather pedantic, and doesn't really capture any of our main points.
See the rest of my reply.
True, but that does not mean that one should learn how the library is
implemented _before_ one learns how to use it. It only means that you will
learn how to use it better _while_ you learn how it is implemented.

Perhaps. See below.
Before worrying about algorithmic complexity, I would worry about
correctness. Since along each path of control flow every new has to match
one and only one delete, dynamic allocation and deallocation introduces a
global state into the program that is very hard to reason about. Moreover,
dynamic m object management interacts very poorly with other language
features such as exceptions and templates: exceptions introduce surprising
paths into control flow. Learning "pointers" early runs the risk of students
developing habits that turn out bad only much later. E.g.:

  template < typename T >
  class example {
    T * left;
    T * right;
    example & operator= ( example const & );
    example ( example const & other );
  public:
     example ( T const & l, T const & r )
       :  left ( new T (l) )
       , right ( new T (r) )
     {}

     ~example ( void ) {
       delete left;
       delete right;
     }
   };

That looks fine, and making it exception safe will clutter the code. Since
it is flawed, however, arguing correctness is impossible or riddled with
many caveats. Using suitable smart pointers or other library components
helps to simplify the arguing considerably. As you cannot (and should not
even try to) teach all at once, I would argue that raw pointers have to wait
until the reasoning powers of the students are up for the task of handling
them correctly. Fortunately, the standard library allows one to do
interesting imperative programming problems way before that point.

Another exercise that exhibits the inherent difficulties of pointers is
this. Explain why the following is not just poor form but may indeed leak:

As long as we agree they should know how std::vector is implemented
eventually, I suppose it's a question of empirical fact as to which
order of learning is best.

As a guess purely on personal preference, I would prefer and I think I
would learn better if I learned how the internals of std::vector work
before hearing the explanation of the interface, contracts, and
guarantees of std::vector.

Also, if I was teaching an intro course for those who would take more
courses, I'm not sure I would focus as heavily on RAII and exception
safety as you do. Correctness of programs is important, but it's not
obvious to me that teaching someone with the use of fully correct
programs from the beginning is the best way to end up with someone who
writes fully correct programs at the end. As a (poor) analogy, I would
teach a student Newtonian physics before I taught them General
Relativity.
  template < typename T >
  class example {
    T * data;
    example & operator= ( example const & );
    example ( example const & other );
  public:
    example ( T const & t ) {
      data = new T;
      *data = t;
    }
    ~example ( void ) {
      delete data;
    }
  };

Indeed. For a sane program, "data = new T;" may succeed, but the
assignment "*data = t;" may throw, causing the constructor to not
finish, causing the lifetime of the object to never begin, causing the
standard invocation of destructor to never occur, causing the "data =
new T;" to never be freed.

However, I remain unconvinced that explaining this in an introduction
to C++ course is the best way to start teaching a new C++ programmer.
 
J

Joshua Maurice

Pascal J. Bourguignon ha scritto:


What about embedding the application into a system which restarts it
automatically upon every crash, or which starts a backup application?

And so it begins. I've seen this loop before, and I did not like it.

Hopefully my only addition to this oft repeated argument is that real
robust applications tend to be robust from "firewalling" or separating
the program into isolated units. In C++ on unix like systems, this is
commonly at the process level. For crazy embedded systems, I've heard
about mission critical applications being written by 3 independent
teams using 3 different algorithms, and there was a small election
holder system isolated from the 3, and it would act on the majority
vote. Any dissenting voter was reset.

C++ programs by their very nature are incredibly brittle and fragile.
One wrong line anywhere can cause the entire process to do very weird
things. To get robustness, isolate and have redundancies, backups,
transactions, failovers and automatic resets, etc.
 

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

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,009
Latest member
GidgetGamb

Latest Threads

Top