19

This is not a question about which of the two languages is better than the other. I myself can't really decide. Pros and cons as always I guess.

Also, if you feel you always would prefer C over C++, this poll is not for you :-).

However, when I work in C projects I usually feel I'm missing a few language constructs more than others, which can be found in C++.

For example, I usually miss (the obvious) classes, but seldomly templates (I always miss STL, but wouldn't call it a language construct).

What do you miss when you have to use C instead of C++?

35

Destructors (for RAII).

I can live without the rest of C++'s OO and templates. But I really miss RAII when programming in C.

35

Standard Templates Library (STL)

24

Flexible declarations. In C, all var declarations within a scope occur at the beginning of that scope. Thus, all global declartions must appear before any functions, and any local declarations must be made before any executable statements.

Fortunately this was changed for C99.

17

Overloading (function, operator and method)

14

I'll get modded down for this, but... I'd miss C++.

Too much features comes with C++, features that I took as granted, and that are removed when going backward to C.

When I learn RAII is mostly absent from C# and Java (despite some interesting "patterns"), I just say to myself "hey, at least, I have their great standard API and language features, and reflection, and etc.!".

Each time I have to degrade C++ code to make it fit into a C something, I don't have the "Hey, at least C has this great feature". Every great feature of C is already present in C++ at zero cost.

Going from C++ to C is just like having your favorite toolkit, and removing all the tools but the hammer.

And then, you look at the screw, and then the hammer, and then the screw again...

Depressing...

Edit : I guess I should answer Konrad in the post:

?I'll get modded down for this? ? apparently. But why? You're absolutely right. Your statement is insightful, to the point and also answers the question. ? Konrad Rudolph

Why? I guess the author wanted a list of reasons, not some random rant about how "C++ was way cooler than C". I read all the reasons already offered, and felt there was nothing I could add.

Still, I felt some thing important was missing, all in all. It was kinda "What C++ feature would you like to see in C?". This made me answer anyway.

After Konrad's answer and some thinking, the missing thing is: C++ is much more than C with additional features. Each of those features have a kind of symbiosis with all the others, and the full language is quite larger than the sum of its components set apart.

This is why no particular feature would miss, as each particular feature would need another feature to work properly, and another, and another...

Conclusion: When you move from a language to another, you always lose things, but you also win other things. But this is not true when moving from C++ to C. In that case, you never win.

14

// what else :)

12

C++'s improved type safety

12

Templates.

12

Exceptions

10

Classes. Guess I have been doing it with classes and OOP for a long time.

10

Real const-correctness.

9

(Another) thing I miss: Not having to typedef my enums/structs. When I need to do straight C, I often forget that I need to type

typedef enum { A, B } alphabet;

instead of

enum alphabet { A, B };
7

Ok, I'll try one last time, this time, keeping to the question.

I'll demonstrate below that nothing is as simple as asking for one feature only, and that with that feature comes others, implicitly.

Note: The code below should be considered as pseudo-code. It won't (obviously) compile if processed by a C compiler, and is written only to illustrate some points.

I Want RAII

This is pretty straightforward, already asked before this post, and nothing spectacular or outrageous, at first glance.

This means that when I acquire resources, and I want them freed in a deterministic way.

In C, we would then need to use structs for that, as they are the only true types the user can define.

struct MyStruct
{
   HANDLE myResource ; /* HANDLE is some type of resource */
} ;

For that, I need to code a destructor for MyStruct, because we assume HANDLE is not RAII powered.

For RAII, we need a Destructor?

But how to code a destructor in C?

There are several ways. Some will be C code, others will need extension to the language.

Destructor as an external function?

We could try a function inside the structure, but this is not C. So we'll try instead an external function.

For example:

struct MyStruct
{
   HANDLE myResource ;
} ;

void finalize(MyStruct * myStruct)
{ deallocateSomeResource(myStruct->myResource) ; }

But the name can't be finalize. Unless we can use function overloading in C (which we can't).

The other solution would be to add the name of the class for the finalizer:

void finalize_MyStruct(MyStruct * myStruct)
{ deallocateSomeResource(myStruct->myResource) ; }

Now, this would work... But what if we have collision of symbols?

I mean, perhaps I already have a structure called finalize_MyStruct !!!

Forbid use of prefix "finalize_"?

Why not. After all, if in C++, the standard forbids the use of symbols prefixed by "_", then we could change the C standard to forbid any symbol prefixed by "finalize_".

Still, this would perhaps break some valid code...

Using the name of the struct?

Another solution would be to re-use the name of the struct:

struct MyStruct
{
   HANDLE myResource ;
} ;

void ~MyStruct(MyStruct * myStruct)
{ deallocateSomeResource(myStruct->myResource) ; }

So we would need an extention of C to accept a function with the same name of a struct, prefixed by a "~", which would be considered as the destructor of the struct.

We could add a little syntactic sugar, like the this keyword, and put the function inside the struct, but this is not mandatory. Isn't it?

Now, this would work: Now, with the extension, C can destroy any MyStruct allocated on the stack:

void doSomething()
{
   MyStruct oMyStruct ;
   oMyStruct.myResource = allocateSomeResource() ;
   /* etc. */
}  /* At the end of the scope, have the compiler call ~MyStruct(&oMyStruct) */

And what if the headers are broken?

This could happen:

/* HeaderA.h */
struct MyStruct
{
   HANDLE myResource ;
} ;

/* HeaderB.h */
void ~MyStruct(MyStruct * myStruct) ;

/* SourceB.cpp */
void ~MyStruct(MyStruct * myStruct)
{ deallocateSomeResource(myStruct->myResource) ; }

/* SourceOne.h */
#include "HeaderA.h"

void doSomething()
{
   MyStruct oMyStruct ;
   oMyStruct.myResource = allocateSomeResource() ;
   /* etc. */
}  /* At the end of the scope, nothing happens as no destructor visible */

/* SourceTwo.h */

#include "HeaderA.h"
#include "HeaderB.h"

void doSomethingElse()
{
   MyStruct oMyStruct ;
   oMyStruct.myResource = allocateSomeResource() ;
   /* etc. */
}  /* At the end of the scope, call ~MyStruct(&oMyStruct) */

In doSomething(), as no destructor declaration was visible, the object will leak. In doSomethingElse(), everything is ok.

So it means we must tie together MyStruct and its destructor... By putting it in the struct?

Destructor as an internal function?

We can add another extension to the C language to tie the struct and its destructor by putting them together:

struct MyStruct
{
   HANDLE myResource ;

   void ~MyStruct(MyStruct * myStruct)
   { deallocateSomeResource(myStruct->myResource) ; }
} ;

Again, the this keyword would have been cool, but not necessary.

So, we can know have RAII, isn't it?

No.

Because this code would crash:

void doSomething()
{
   MyStruct oMyStruct ;

}  // At the end of the scope, call ~MyStruct(&oMyStruct)

Because oMyStruct was not correctly initialized, and thus, oMyStruct.myResource has an invalid value.

So it means we need an... Initializer!!!

For RAII, we need a Constructor?

We'll follow the convention adopted above. This means the following code:

struct MyStruct
{
   HANDLE myResource ;

   void MyStruct(MyStruct * myStruct)
   { allocateSomeResource(myStruct->myResource) ; }
   void ~MyStruct(MyStruct * myStruct)
   { deallocateSomeResource(myStruct->myResource) ; }
} ;

Cool. Now, RAII works, doesn't it? Well, not quite:

void doSomething()
{
   /* create one pMyStruct on the heap */
   MyStruct * pMyStruct = malloc(sizeof(MyStruct));

   /* Etc. */

   free(pMyStruct) ;
}

Malloc will only return free memory. The user must initialize it by hand. And free will only free the memory. The user must finalize it by hand...

So we need... new and delete !!!

For RAII, we need a new and delete?

The first idea would be to add functions inside the struct, but this would be quite tedious. So we will use C macros!!!!

#define NEW(type, pointer)                       \
do                                               \
{                                                \
   pointer = malloc(sizeof(type)) ;              \
   type(pointer) ;                               \
}                                                \
while(false)

#define DELETE(type, pointer)                    \
do                                               \
{                                                \
   ~type(pointer) ;                              \
   pointer = free(pointer) ;                     \
}                                                \
while(false)

But of course, the compiler could generate at compile time the code, instead or relying on macros. But the idea is here..

Cool. Now, RAII works, doesn't it? Well, not quite, as seen in the following code:

void doSomething()
{
   /* create 25 pMyStruct on the heap */
   MyStruct * pMyStruct = malloc(sizeof(MyStruct) * 25);

   /* Etc. */

   free(pMyStruct) ;
}

For RAII, we need a new[] and delete[], too?

Same problem than with new and delete. Same solution.

So I guess that everything's Ok, no? For example, the following code:

void doSomething(MyStruct p_oMyStruct)
{
   /* Etc. */

   p_oMyStruct = getAnotherStruct() ;

   /* Etc. */
}

Oops, no...

For RAII, we need a copy-constructor and an assignment function?

struct MyStruct
{
   HANDLE myResource ;

   void MyStruct(MyStruct * myStruct)
   { allocateSomeResource(myStruct->myResource) ; }
   void MyStruct(MyStruct * myStruct, MyStruct * myCopy)
   { allocateSomeResourceByCopy(myStruct->myResource, myCopy->myResource) ; }
   void operator = (MyStruct * myStruct, MyStruct * myCopy)
   {
      deallocateSomeResource(myStruct->myResource) ;
      allocateSomeResourceByCopy(myStruct->myResource, myCopy->myResource) ;
   }
   void ~MyStruct(MyStruct * myStruct)
   { deallocateSomeResource(myStruct->myResource) ; }
} ;

I won't elaborate on the fact that we have function overloading, again. This time, between the default constructor and the copy constructor. This means three cases, all in all, of function overloading. This can be handled silently by the compiler (indeed, C does a little of overloading on its own), so I won't mention it too much.

Conclusion?

Just mention one C++ feature you like, and you'll see most will come attached to it.

Conclusion, for adding RAII to C, we would need to add to C the following extensions, with a syntax similar to C++:

  • A Destructor
  • A Constructor
  • struct methods inside struct
  • new/delete
  • new[]/delete[]
  • Copy Constructor
  • operator = Overloading

And some syntactic bonus would be interesting:

  • this keyword
  • function overloading

And, all in all, I believe there are still some things I forgot, needing more C++ features.

6

Templates, type safety, mixed declarations and code (pre-C99), const correctness, a library worth a damn, RAII.

6
  1. The ability to shoot myself in the foot more than once, with the same bullet
5

Nothing.

I love c++, and would always use it where I can, but when I need to use C it's because I need to be close to the machine, and have a clear idea of exactly where and when resources are in use. Classes and containers suddenly feel heavy and unwieldy, like swimming in mud.

Back on my Mac, though, with infinite memory and disk space it's classes and containers all the way.

5

One of the things I miss is namespaces, to keep function/variable names from colliding.

5

The string class. Whenever I'm in C code and have to deal with strings, it feels like pulling teeth compared to how much more natural it is in C++.

Of course C++ gets that capability mainly due to RAII (and I've up-voted Rasmus Faber's answer accordingly), but still it's strings where I feel the loss most immediately.

5

Boost and all the frameworks and libraries that you can use to make your life easier.

4

Classes and OOP
Overloading
Virtual Functions (We can achieve this, but lot more effort required)

4

new and delete operator

4

More than anything else: Inheritance. The ability to factor out common functionality into a base class/struct.

3

I don't miss classes until some way down the track. It starts with a struct here and there, then an init and free method, a few other methods and suddenly I'm half way down the path of implementing classes.

But, I don't miss classes. What I miss is collections and useful types: strings, lists, dictionaries and so on. When banging out a quick app, it's these things which make the difference.

PS: C99 has var declarations at any point, and most of the other nice little improvements of C++. So I don't miss these things.

3

The ability to declare a loop variable in the loop declaration. E.g.

for(int i = 0; i < 10; i++)  // Invalid C
{
    //Do something
}
2

I guess I wouldn't miss classes or templates if it weren't for the STL. The data structures it provides are nice and annoying to implement yourself in C even if they are trivial. I'd really rather avoid implementing yet another vector or whatever.

2

method parameters passed by reference

1

Templates/exceptions and sense of humor!

1

dynamic casting

1

Stack based resource management

FileCloser closer(fp); // closes the FILE * on function exit
0

I miss: classes; new; delete; inheritance. I hate the fact that every time I use a struct variable, I have to write "struct"; e.g. a function that says *foo(struct struct_name s)*. I hate the lack of // comments. I abhor the lack of a string class and the vector class from the STL. I shudder at the thought of not being able to create a datatype with its own operators.

I'm a C++ junkie, and have been for nine years. :-)

0

The same things I would miss if I had to program in the unnamed language instead of C++. C and C++ might have common keywords (as do javascript and java), one might have evolved from the other (as did D from C++), but when I code C I take fundementally different approaches to the problem. So the answer would be Mu.