13 Nov 2007 redi   » (Master)

Three cheers for writing documentation

Last week I thought I'd finished implementing Improving shared_ptr for C++0x for GCC: GNU Compiler Collection but have spent the last few days writing more tests and docs on the implementation.

Writing the docs resulted in far larger code changes than the additional testing with funky types and debug allocators. Testing found that I was using the wrong allocator type in one place (so potentially leaking memory, not good for a shared_ptr!) and that I needed to remove a const-qualifier somewhere else, easy with this shiny new std::remove_const meta-function. Only about 5 lines to change. Documenting the "finished" design resulted in several simplifications, a better interface, and the complete removal of some unnecessary code. The difference is partly because my original tests covered most cases, but it still makes me think of Richard Feynman's point that if you can't explain something in simple terms, you don't really understand it. (The much paraphrased original seems to be "I couldn't reduce it to the freshman level. That means we really don't understand it.") Explaining why I'd made certain compromises in the design embarassed me into fixing them, and documenting the unresolved issues made me decide to resolve some of them and give a decent rationale for leaving the others.

I wish I could give the same amount of time to designing, documenting and refactoring some of the code I'm paid to write, but my open-source dabbling benefits from having no deadlines. The shared_ptr changes have been brewing for months. The downside is that some of my PStreams ideas have been idling on a hard disk for years. I really must fix showmanyc.

Cool new C++ feature

C++0x introduces the following function:


template<class T, class... Args>
  shared_ptr<T> make_shared(Args&&... args);

Which is used like so:


class A {
  A(int);
  // ...
};
shared_ptr<A> p = make_shared<A>(99);
// better than: shared_ptr<A> p(new A(99));

This function is cool for two reasons.

First, it only needs a single allocation for the A and the shared_ptr's internal bookkeeping.

Secondly, it gives the strong exception-safety guarantee. Consider:


void f(shared_ptr<A>, shared_ptr<A>);


f(shared_ptr<A>(new A(1)), shared_ptr<A>(new A(2)));

Because C++ doesn't define the order of evaluation here, the compiler is allowed to perform both new operations before calling either shared_ptr constructor. If the second allocation or construction throws an exception, the first object will be leaked.

Today, the usual way to avoid the leak is to avoid calling new twice in that one statement (using a local variable instead of one of the temporaries,) but in The Future we will be able to say:


f(make_shared<A>(1), make_shared<A>(2));
This cannot leak, because both A objects are safely managed by a shared_ptr as soon as they're constructed. RAII to the maaaaaaaax.

So it's cool because it's safer and more efficient. It's one less reason to see naked new delete operators in C++ code.

make_shared() is possible as a library in C++03, but with variadic templates and rvalue-references in C++0x it's really cool. Try it out in GCC 4.3 soon (I hope.)

Latest blog entries     Older blog entries

New Advogato Features

New HTML Parser: The long-awaited libxml2 based HTML parser code is live. It needs further work but already handles most markup better than the original parser.

Keep up with the latest Advogato features by reading the Advogato status blog.

If you're a C programmer with some spare time, take a look at the mod_virgule project page and help us with one of the tasks on the ToDo list!