Why C++’s new is badly designed

I must first confess I didn’t read the standard thoroughly. It’s not that important – there’s one huge flaw in the design of C++’s new that makes it quite hard to have good things like encapsulation.

Theoretically, that’s what the header–source file split is for. That’s why we have to deal with the preprocessor mess, because we want this sort of encapsulation, where we only expose the interface, leaving the implementation details to be just that – a detail.

However, this doesn’t work quite well from C++’s perspective. First of all, you have to place in the headers the full definition of the class – including the private members – this means that you have to expose the full signature of the class. Certainly, you can use the pimpl idiom, but that is a simple way to take down the performance. However, you expose the contents of your class, making it quite easy to access private members (one just has to take the address of the class, and modify the contents at a certain offset). Data encapsulation can be broken with full understanding of the contents of a class.

And we get to the most important, which is breaking by design a basic principle: encapsulation itself. Each user of the header file has to calculate the dimension of the class whenever it calls ‘new’ – I refer during compile time. Basically, the calculation of the dimension of the class in memory should be done in one place alone, in the class definition. Let’s create an example to demonstrate:

This is the current logic for instantiation of a type (simplified). Note that the caller (the compiler of your unit) has to know the correct sizes of all the members – and this is not really possible since the sum is not calculated the same with different compiler parameters. It cares about private members and protected members as well. When, in fact, the only thing it should care about is the size of the type. In a pure OOP approach, the CppType would be able to tell the size of an object of that type. Like so:

This will actually make it a lot easier for a clear C++ ABI. This way you’d be able to deliver binaries with C++ code – without caring much about the data sizes except where you interact with the class – public members and methods.

The story isn’t complete, though. There are obvious up-sides to this bad choice, mostly the fact that you don’t have to have a specialized virtual call to create a new object, but they really break the beautiful parts of C (in C there is no such nonsense as publishing private members)

Funny enough, I wrote this article and didn’t really feel like publishing it, kind of tired of the brain dead “C++ is perfect, you don’t know C++, who the heck are you” crowd. But I ran into Uncle Bob’s presentation on design principles and he makes here a history of some of the design decisions that were made in our various languages. He also points out that C++’s decision to have the headers polluted with information that shouldn’t really be available to everyone (like what private members I want to use or what private methods I must use, even if they are not virtual) is quite a bad one.

Comentariul tău