Joshua said:
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.
Perhaps. See below.
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.
Very, very much agreed.
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.
The point is not to teach RAII early on. The point is to use the library and
teach safe idioms early so that reasoning becomes simpler. In effect, I
would introduce RAII probably in the context of pointers: new and delete
have to be matched in pairs (that mantra, I would strongly reinforce when
teaching pointers); the language guarantees that constructors and
destructors of a given object are paired along all paths of flow control.
So, let's new in the constructor and delete in the destructor and let the
guarantees of C++ take care of that part of reasoning.
However, as I would teach pointers somewhat late in the process, RAII would
also come somewhat late.
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.
There might be a slight misunderstanding: I would not even try to explain
that to a beginner. But when diving into pointers, I would feel the need to
explain something like that (maybe just in order to prevent bad coding
habits from being established). Hence, I would not explain pointers to
beginners and start elsewhere.
Here is a rough order that comes to mind:
* basic types: int, double, std::string.
* flow control.
* buildings complex types: classes and containers.
* standard library: iterators, algorithms, streams.
* function objects.
* exceptions and flow control via throw/catch.
* templates.
* smart pointers (e.g., tr1::shared_ptr<>, tr1::function<> )
* raw pointers and arrays.
* implementing all those nifty library features.
The elegance of pointers is that they can serve as a building block for so
many other things. But that power comes at the price of some huge (albeit
hidden) complexity.
Best
Kai-Uwe Bux