While C may have restrict pointers, I think C++'s templates takes the win in C vs C++.
If you want both generalization and optimization, you can't expect void pointers and function pointers to help the compiler optimize your code. A widely cited example is C qsort() versus std::sort(). The latter is always faster because the compiler knows more about the types it's working with. For example, the qsort() compare function pointer now becomes a single instruction rather than an indirect function call.
Templates are the best thing about C++ and there is absolutely nothing in C that compares.
The next biggest advantage of C++ over C is STL. You get
- Standard data structures
- Standard algorithms (especially powerful in C++11)
And these are all type-aware! There are no void pointers for storing arbitrary data or finicky macros for efficient data structure manipulation. And as mentioned above, the compiler can make more informed optimizations since type information is known at compile time.
Less used, but templates can even be used to work the compiler (e.g. do complicated calculations at compile-time ... like generalized loop unrolling or computation of constants).
While there are many examples of C++ abused, judicious use of its features can help with code maintainability, convenience, and optimization. Take for example function pointers with void arguments used for callbacks. It would look something like:
Code:
void do_something(void (*callback)(void *), void *arg);
The the void *arg is synonymous to an instance of an object in C++. In fact, it's entirely the same as
Code:
struct Callback {
void operator()() {
// 'this' pointer [b]is[/b] 'arg' above
// Oh yeah, and no casting void pointers ... the type is always known
DoSomething(someData);
}
// Argument information is member data
SomeDataType someData;
};
How about initialization and cleanup? In C, you'd do something like:
Code:
void do_something() {
struct my_thing *thing;
thing = my_thing_alloc();
if (!my_thing_do_something(thing)) {
/* Oops, forgot my_thing_free(thing)! */
return;
}
/* ... */
my_thing_free(thing);
}
In C++, at no extra cost and less code you get automatic initialization and cleanup
Code:
class MyThing {
MyThing() {
// Initialize data
}
~MyThing() {
// Cleanup data
}
bool DoSomething();
};
void do_something() {
MyThing thing;
if (!thing.DoSomething()) {
// Destructor called here automatically
return;
}
// Destructor called here automatically
}
It's especially useful with resources like files or memory. There's just less chance of programmer error. For example:
Code:
void do_something() {
FILE *file = fopen("thing.txt","r");
/* ... */
if (something_failed) {
/* forgot fclose(file) */
return;
}
fclose(file);
}
In C++
Code:
void do_something() {
std::ifstream fileStream("thing.txt");
// ...
if (something_failed)
return; // Destructor closes file here
// Destructor closes file here
}
Upshot:
C++ gives you more control over C (templates) and offers an impressive arsenal of standard data structures and algorithms.
Miscellaneous:
Take a look at the CUDA
thrust examples. In C, this kind of GPGPU programming would be substantially more complicated! The thrust interface behaves just like the generalized STL interface (and at no real extra cost!).