After helping 3M move
Lava C.O.S. to a great new team in St. Paul, I've started work with someone
new project which involves some C++ programming, this time with Visual Studio 2010, which includes several important C++0x features I had been introduced to in
David Musser's Generic Programming course in grad school.
The most interesting (and at first baffling) is
rvalue references. They have the dubious syntax of && but are not a reference to a reference (whatever that would mean); it is a special type of reference that at compile time is known to be basically an unnamed temporary. Having this distinction lets you do a number of interesting optimizations related to moving objects around; so-called move semantics.
Suppose a function has returned to you a std::vector, as in:
std::vector
x = makeGiantVector();
Now, the compiler may be able to optimize that, but it can't always. When it can't you have to construct a new vector, copy every element from the temporary that was returned, then delete the memory of the temporary. Since std::vector is heap-allocated, you would like to have the above line act like this:
std::vector tmp;
makeGiantVectorByReference(tmp);
std::vector x;
std::swap(tmp, x);
That is, we want to be able to steal the memory used by the temporary rather than copy it only to delete it. C++0x does this by letting temporaries like the values returned from a function bind to an "rvalue reference", so std::vector can have a constructor that takes temporaries and steals the memory. This is safe because the compiler only gives you rvalue references to temporaries. The constructors look like this:
vector(const vector& v) {
_beg = new T[v.size()];
_end = _beg + v.size();
_endOfStorage = _end;
copy(v.begin(), v.end(), begin());
}
vector(vector&& v) :
_beg(v._beg),
_end(v._end),
_endOfStorage(v._endOfStorage)
{
if (this != &v) {
v._beg = NULL;
v._end = NULL;
v._endOfStorage = NULL;
}
}
You can also overload the assignment operator with an rvalue reference, of course.
This is a nice optimization. The neat part is that this one feature gives you the ability to move things:
std::vector x = foo();
std::vector y = bar();
...
y = static_cast&&>(x);
Now y contains what x did but we let x lose what it was holding in the process. That's ugly syntax, so the standard provides a function with much better syntax:
std::vector x = foo();
std::vector y = bar();
...
y = std::move(x);
More to come. In particular, auto_ptr is deprecated, long live unique_ptr, which is based on the above.
A good reference.