Log in

C++0x! - Ben FrantzDale [entries|archive|friends|userinfo]
Ben FrantzDale

[ userinfo | livejournal userinfo ]
[ archive | journal archive ]

C++0x! [Mar. 28th, 2011|07:41 pm]
Ben FrantzDale

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<int>, as in:
std::vector<int> 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<int>, 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<int> tmp;
std::vector<int> 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) : 

  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<int> x = foo();
std::vector<int> y = bar();

y = static_cast<std::vector<int>&&>(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<int> x = foo();
std::vector<int> 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.

[User Picture]From: tdw
2011-03-29 12:02 am (UTC)
auto_ptr was the worst good idea of all time.
(Reply) (Thread)
[User Picture]From: benfrantzdale
2011-03-29 01:36 am (UTC)
Seriously? Aside from the gotcha that rvalue references fix and the gotcha that they don't belong in standard containers, what's wrong with them? Once you get over those two (really one) issues, they are beautiful. What other type should a factory return? In particular, I'm thinking of what I learned from this post: http://www.gotw.ca/publications/using_auto_ptr_effectively.htm
(Reply) (Parent) (Thread)
[User Picture]From: tdw
2011-03-29 01:44 am (UTC)
Historically, my problem with them has been that a) they are not idiomatic in most / all C++ environments and a') if your codebase wasn't written with them in mind then they cause significant surprise.

Right after learning about them I thought it was brilliant, pushed to make it common at JetHead, and shortly thereafter wound up burned repeatedly. They just don't behave like any other C++ objects, don't fit with people's existing models, and are generally dragonlike (subtle, quick to anger.)
(Reply) (Parent) (Thread)
[User Picture]From: benfrantzdale
2011-03-29 02:42 am (UTC)
I've never felt burned by auto_ptr, although it is idiomatic. Care to give examples?
(Reply) (Parent) (Thread)