views:

1678

answers:

31

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++?

+12  A: 

C++'s improved type safety

Leon Timmermans
+12  A: 

Templates.

smink
+10  A: 

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

smink
+17  A: 

Overloading (function, operator and method)

Leon Timmermans
At least one C compiler has vendor-specific extensions for that
Friedrich
+24  A: 

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.

smink
+1 But fortunately that has been changed in C99.
Rasmus Faber
James Curran
Indeed! Backporting from C++ to C is hell when facing this constraint.
sharkin
And Microsoft *still* hasn't fixed Visual Studio's C compiler so it follows the standard! I hate it! And yes, there is a flag to compile your C files as C++, but that is not always feasible. Did I mention that I hate this?
Thomas Padron-McCarthy
+10  A: 

Real const-correctness.

Leon Timmermans
+12  A: 

Exceptions

Leon Timmermans
Their absence is my favourite thing about C ;)
Mark Baker
Each one his own...
Leon Timmermans
Read Joel Article about exceptions may be you will miss it less :) http://www.joelonsoftware.com/items/2003/10/13.html
Ilya
Strange that so much people thought differently. Considering both J. Spolsky on one hand, and people like H. Sutter, S. Meyers, B. Stroustrup on the other... And considering the latter are C++ gurus, I guess I just prefer exceptions to return codes. That, or the fact too many errors because of them.
paercebal
Exceptions +1. I just had to maintain a library using error codes. Guess what: most were not checked, reporting was poor (no detail, only numeric codes), useful code was mixed with 25% of errors management. Awful and a pain to maintain.I just replaced everything by exceptions, that I catch in strategic locations. Code is now simpler, elegant, no error is leaking, memory is cleaned-up in case of error, and bonus, errors now carry a code, but also additional info: name of missing file and such.
Jem
+3  A: 

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.

Jonathan Wright
+35  A: 

Destructors (for RAII).

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

Rasmus Faber
That's so true. RAII is an invaluable technique that I miss in a lot of other languages.
Leon Timmermans
don't really care about RAII, but destructors are handy
Matt Joiner
+2  A: 

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.

Jon
+1  A: 

Templates/exceptions and sense of humor!

Erick Sgarbi
+35  A: 

Standard Templates Library (STL)

PW
I would probably say the same myself, funny that a library can get so popular and de-facto that you almost forget it's not a language construct :-)
sharkin
templates made this work, but beside using STL, I need them very rarely
PW
+6  A: 

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

DrPizza
there isn't a c++ library worth a damn. a c++ world with no c libraries would be a hollow, obfuscated, and thoroughly awful world, quickly overrun by java and c#. c++ by itself would never last long.
Matt Joiner
False; C++ has its own Standard Library and e.g. Boost, Intel TBB, and others. C has nothing like this, to its great detriment.
DrPizza
+4  A: 

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

TG
Technically, of course, you can achieve anything C++ has to offer with a "lot more effort required".
Rik
@Rik: Not anything. RAII is out of scope of C (pun intended), as well as compile time execution (meta programing) and exceptions.
paercebal
+1  A: 

dynamic casting

m_pGladiator
+2  A: 

method parameters passed by reference

m_pGladiator
+4  A: 

new and delete operator

m_pGladiator
What do new/delete provide that malloc/free don't? Or do you mean constructors/destructors?
KeithB
with new operator we don't care about the sizeof(allocated) and with delete [] we can delete array of objects with one line.
m_pGladiator
delete is one prerequesite to have destructors, and thus, RAII.
paercebal
+4  A: 

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

Vulcan Eager
nah sif, it really isn't that great.
Matt Joiner
+14  A: 

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.

paercebal
“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
C is less complex than C++ (a virtue in so many cases). In vast projects it's much easier to shoot yourself in the foot with C++ than C. The concept of "winning" takes more nuance than "features per langugage" to define.
sharkin
And yes, my first sentence in this question was to avoid posts like this :)
sharkin
"In vast projects it's much easier to shoot yourself in the foot with C++ than C" : I disagree with this assertion, which explains my "you never win". But generations of coders did the debate in the past, and this was not the point of the topic... :-p
paercebal
"And yes, my first sentence in this question was to avoid posts like this :)" Still, my answer comes from painful personal experience of delving in C code. "Everything" would have been less clear than my answer ;-). Perhaps the question should have been "What non-C C++ feature to you like/use more"
paercebal
My "assertion" is not based on debate or popular opinion, it's based on experience and results. There has indeed been substantial debate on this topic, perhaps not the loudest of them all, as you point out.
sharkin
"Perhaps the question should have been "What non-C C++ feature to you like/use more""This question is good enough. I suggest you do a poll on any aspect you like, I would definetely upvote any polls of this kind.
sharkin
"it's based on experience and results": I am sorry to read that.
paercebal
No need to be sorry. I'm not saying C++ is a bad language. Far from it. It's just about pros and cons.
sharkin
Anyone who says it is easier to shoot yourself in the foot with C++ has never seen a C program that has become MACRO soup.
jmucchiello
i absolutely cannot agree with your final comment about always losing when going to C from C++. this is heresy
Matt Joiner
@Anacrolix: :-D
paercebal
+5  A: 

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.

David Sykes
+14  A: 

// what else :)

FooLman
C99 has that ;).
Terminus
+6  A: 
  1. The ability to shoot myself in the foot more than once, with the same bullet
Kris
yeah i really miss that in c++. and spewing template and linker errors while getting plugged with more bullets.
Matt Joiner
+1  A: 

Stack based resource management

FileCloser closer(fp); // closes the FILE * on function exit
plinth
+5  A: 

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

Caleb Huitt - cjhuitt
+9  A: 

(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 };
Caleb Huitt - cjhuitt
+7  A: 

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.

paercebal
-1 since this post is riddled with factual errors about what can be done in C.
sharkin
I'm at loss: I spoke nowhere in my post of what can be done in C. To the contrary, I summed up what things impossible in C should become possible to make RAII possible. Still, my C knowledge is not so advanced as yours, so I humbly bow to your mastery... :-p
paercebal
You use C-code examples to build up an argument. This is a good way to show the point, but the errors goes far beyond pseudo-some-things-may-not-compile. You use constructs which doesn't exist, which is at the core of your argument. And it's misleading. And it's not advanced knowledge. -1, sorry.
sharkin
No, Paer is demonstrating the hassle involved in building a C++ concept in C and how C presents difficulties to doing so.
Paul Nathan
Yes he does. I point this out in my comment. But the C-code he uses isn't legal.And for that matter, RAII can't be achieved in C in this way. Calling the "destructor" at the end of scope? You must to be kidding. RAII is a language construct, not a coding convention.
sharkin
@Robert A: You missed the point. You are saying RAII is impossible in current C, which is true. I enumerated the needed extensions for C to enable the RAII extension for C with example pseudo-code. The aim of all this demo was to show that even a "simple" feature (RAII) needed other features to work
paercebal
Your problem, Robert A, is that my initial point "C++ is not a set of independant features" is proven by my second point "What would be needed to have RAII in C". And apparently, you willingly ignore the demonstration to instead pick at details ("This won't compile in my C99 compliment compiler")
paercebal
All in all, it's not important. The point was made with RAII. I could easily reproduce similar reasoning with exceptions, or namespaces. And if by reading all the answers, one will see the majority of desired features would fall in the category "dependent of another feature" (STL, indeed...). ^_^
paercebal
Well, this poll was not about what it would require on technical level to have the features you miss from C++ implemented in C. People answer with the language construct they find most useful in day-to-day work, without getting into the practical requirements involved to actually implement it.
sharkin
I think most of us know what it would require to create C++ from C. Your post is the answer to the question "Why can't they just update C with struct-destructors?".
sharkin
My first answer: "Well, I guess I would miss a large part of C++ because every single part I miss have dependencies, and all in all, C++ isn't just C with a bunch of features.". This answer is a demonstration of my first one, showing, perhaps, that the question was more complex than estimated.
paercebal
The fact is that most people are not answering just one "language construct they find most useful", but a lot of constructs, both explicitly or implicitly (e.g., the STL is the greatest implicit one). I am giving the same answer, but with justification attached. I stick to my answers.
paercebal
+5  A: 

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.

Michael Burr
c++ strings have got nothing on strings in other languages. they're convenient for a Cish language, but pretty clunky.
Matt Joiner
@Anacrolix - no argument from me.
Michael Burr
+5  A: 

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

rshimoda
+3  A: 

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

for(int i = 0; i < 10; i++)  // Invalid C
{
    //Do something
}
Cristián Romo
Note that this is valid C (C99) for ten years already.
Juliano
A: 

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. :-)

Paul Nathan
You can use typedef to eliminate the need for saying "struct" everywhere.
Kyle Cronin
typedef won't eliminate the need for struct. For example, in forward declarations, typedef are unusable. The good news is that the need for typedef was removed by C99 (apparently, one of the few things that could be backported from C++ to C... Noting that even "bool" didn't make it).
paercebal
actually bool did make it, not the same way as in c++, but close enough.
Matt Joiner
A: 

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.

soulmerge