Most programers already have heard of it: There will be a new C++ ISO standard. It's in the making for quite some time now and compiler vendors already have implemented a lot of the features. It's commonly refered to as C++0x as people expected it to appear somewhere in 200x. Now it seems to become C++11, maybe C++12.
The changes are huge and looking at C++0x source code is like looking at a new language. It has both, new core language features and useful additions to the STL. In this post I'll introduce the feature of which I think that they will change the way C++ is used the most.
shared_ptr
shared_ptr
is an addition to the STL. It's a template class std::shared_ptr<T>
that implements
a reference counting pointer. Reference counting is a commonly known technique to C++ programmers and every
big codebase seems to have it's own implementation. They are also refered to as smart pointers.
The idea is simple: Instead of using raw pointers,
you pass the pointer into an object that overloads the *
and ->
operators so you can use
the object like a pointer. But additionally the object has a reference counter attached. Every
time you make a copy of that pointer object, the reference counter is increased. Uppon destruction,
the reference counter is decreased. If the reference counter goes down to 0, delete
is called.
Now the big advantage of having this in the STL means, that we can easily pass shared_ptr
in
interfaces.
Constructing shared_ptr
works like this:
#include <string>
#include <iostream>
#include <memory>
using namespace std;
int main(int, char**) {
shared_ptr<string> hello = shared_ptr<string>(new string("Hello World!"));
cout << *hello << endl;
return 0;
}
As you can see, there is no delete
. Usually this was a memory leak, but shared_ptr
will call
delete
for us. Common shared_ptr
implementations create an internal refcounter object on the
heap, so you will have 2 new
calls. Using the make_shared
template function can even
eliminate that and it's also shorter:
shared_ptr<string> hello = make_shared<string>("Hello World!");
You can pass around copies of hello
as you like, the refcounter will make sure it stays alive
as long as needed. Using shared_ptr
almost feels like garbage collection in C++. There
is one situation where reference counting fails: cycles. Think of a tree where parents know
their children and children know their parents. If you use shared_ptr
for both, forward and backward
links, you have a strong cycle and the refcounters will never go down to 0.
That's what weak_ptr
is for. You can make a weak_ptr
from a shared_ptr
. weak_ptr
get's notified
when the object it points to is destructed, so you won't get dangling pointers.
To access an object behind a weak_ptr
, you have to call lock()
on it. This will return a shared_ptr
.
My prediction is, that C++ libraries will soon start to use smart pointers extensively
and that will make C++ a better language.
If you want to learn more about smart pointers I can suggest the "Advanced STL" video lecture series by Stephan T. Lavavej on channel 9 . In part 3 he discusses everything about smart pointers.
auto
The auto
keyword is a new core language feature. It implements L-value type inference which is an
idea that most prominently is used in the Go language. In any assignment statement, there is an L-value
which is on the left side of the =
operator and an R-value (on the right side) which is the result
of an evaluated expression.
The R-value already has a strict type. When the L-value is a definition of a new variable, most of the time
you want it to have the type of the R-value. And since your compiler already knows that type, you can now
just tell it to use it:
auto hello = make_shared<string>("Hello World!");
hello
now has exactly the type std::shared_ptr<std::string>
. This might not seem to be
that important, but it greatly improves readability and coding speed in C++.
lambdas
In one of my last posts, I explained why the STL algorithms are decoupled from the containers they work on.
Now some of these algorithms, most prominently for_each
, require a function that will be used / applied uppon
the elements in the container. Modern dynamic languages like python long support functions as arguments, not to
mention functional languages.
C++03 did too, but the syntax was verbose. You could either pass a function pointer to a real function or implement
a callable function object (an object which has the ()
operator overloaded). Both were to complicated
and it was much easier to write a simple for
loop then to use for_each
. Now lambda expressions change that.
Take a look at this simple example:
vector<int> a_list;
for_each(a_list.begin(); a_list.end();
[](int x) { cout << x << endl; }
);
There is a lot more to lambdas, which I haven't even fully explored myself. E.g. using notations like [&]
or [=]
you can access the variable in the lambdas scope. You can read some more in
the wikipedia section about C++0x lambdas.
Lambdas will greatly increase the power and expressiveness of the language and will help improve the
functional style parts of C++.
function / bind
A std::function
is a typed callable object. It is typed on it's inputs and outputs and can be constructed from
a variety of constructs: raw function pointers, function objects, lambdas and binds.
Using std::function
it is easy to setup callbacks / signaling mechanisms in a typesafe C++ manner.
The classic example is a button onClick event:
class Button {
public:
void setOnClickEvent(std::function<void (void)> event) {
onClickEvent = event;
}
private:
void performOnClick() {
if(onClickEvent) {
onClickEvent();
}
}
std::function<void (void)> onClickEvent;
};
The std::bind
is a first order function object -- a function that has some arguments saturated, while others are left to be filled.
It looks like this:
void repeatedBeep(unsigned int x) {
for(unsigned int i=0; i<x; ++i) {
//...
}
}
int main(int, char**) {
Button button;
button.setOnClick( std::bind(repeatedBeep, 42) );
//...
}
Arguments in a std::bind
can also be other function objects which then results in a higher order function object. Wheeee... functional
programming in C++ :)
Admitted, you can do lot's of stupid stuff with binds and functions (and lambdas), exspecially if your arguments go out of scope where
you have passed references. But as always: C++ assumes the intelligent programmer. ;)
I guess when C++0x is in all stable mainstream compilers, we will see a new generation of GUI libraries which will make good use of these
facilities.
There is a lot more to C++0x, but most of them are details which make a difference for the hard-core library implementer. The features above are what I think will influence our every day code and architecture. And I don't know what you think, but I'm pretty excited about these new features.