Re: Compiling C++ modules

Avi Kivity
2006-04-25T07:08:06Z

[de-cc'ed original poster, he's far away by now]

Kyle Moffett wrote:
> On Apr 24, 2006, at 17:03:46, Avi Kivity wrote:
>> Alan Cox wrote:
>>> There are a few anti C++ bigots around too, but the kernel choice of
>>> C was based both on rational choices and experimentation early on
>>> with the C++ compiler.
>>
>> Times have changed, though. The C++ compiler is much better now, and
>> the recent slew of error handling bugs shows that C is a very unsafe
>> language.
>>
>> I think it's easy to show that the equivalent C++ code would be
>> shorter, faster, and safer.
>
> Really? What features exactly does C++ have over C that you think
> make that true? Implicit memory allocation? Exceptions? Operator
> overloading? Tendency to use StudlyCaps? What else can C++ do that C
> can not?
>
> For example, I could write the following:
>
> class Foo {
> public:
> Foo() { /* ... init code ... */ }
> ~Foo() { /* ... free code ... */ }
> int do_thing(int arg) { /* ... code ... */ }
>
> private:
> int data_member;
> };
>
> Or I could write it like this:
>
> struct foo {
> int data_member;
> };
>
> int foo_init() { /* ... init code ... */ }
> int foo_destroy() { /* ... free code ... */ }
> int foo_do_thing(int arg) { /* ... code ... */ }
>
>
> The "advantages" of the former over the latter:
>
> (1) Without exceptions (which are fragile in a kernel), the former
> can't return an error instead of initializing the Foo.
Don't discount exceptions so fast. They're exactly what makes the code
clearer and more robust.

A very large proportion of error handling consists of:
- detect the error
- undo local changes (freeing memory and unlocking spinlocks)
- propagate the error

Exceptions make that fully automatic. The kernel uses a mix of gotos and
alternate returns which bloat the code and are incredibly error prone.
See the recent 2.6.16.x for examples.
>
> (2) You can't control when you initialize the Foo. For example in
> this code, the "Foo item;" declarations seem to be trivially
> relocatable, even if they're not.
> spin_lock(&foo_lock);
> Foo item1;
> Foo item2;
> spin_unlock(&foo_lock);
They only seem relocatable with your C glasses on. Put on your C++
glasses (much thicker), and initialization no longer seems trivially
movable.

On the other hand, you can replace the C code

{
Foo item1, item2;
int r;

spin_lock(&foo_lock);
if ((r = foo_init(&item1)) < 0) {
spin_unlock(&foo_lock);
return r;
}
if ((r = foo_init(&item2)) < 0) {
foo_destroy(&item1);
spin_unlock(&foo_lock);
return r;
}
foo_destroy(&item2);
foo_destroy(&item1);
spin_unlock(&foo_lock);
return 0;
}

with

{
spinlock_t::guard foo_guard(foo_lock);
Foo item1;
Foo item2;
}

14 lines vs 3, one variable eliminated. How many potential security
vulnerabilities? How much time freed to work on the algorithm/data
structure, not on error handling?
>
> (3) Foo could theoretically implement overloaded operators. How
> exactly is it helpful to do math on structs?
It isn't. It's nice for other application domains (matrix algebra, etc.)
not for kernels.

This mailing list has a full complement of reviewers who can detect
trailing whitespace in a dark room three miles away. Surely they can
spot an attempt to sneak in the "operator" keyword.
> Does that actually make it any easier to understand the code? How
> does it make it more obvious to be able to write a "+" operator that
> allocates memory?
>
Not all C++ features need to be used in the kernel. In fact, not all C++
features need to be used, period. Ever tried to understand code which
uses overloaded operator,() (the comma operator)?

--
error compiling committee.c: too many arguments to function