views:

1469

answers:

20

After discussing with a newly arrived developer in my team, I realized that there are still, in C++, habits of using C constructs because they are supposed to be better (i.e. faster, leaner, prettier, pick your reason).

What are the examples worth sharing, showing a C constructs, compared to the similar C++ construct?

For each example, I need to read the reasons the C++ construct is as good as or even better the original C construct. The aim is to offer alternatives to some C constructs that are considered somewhat dangerous/unsafe in C++ code (C++0x valid only answers are accepted as long as clearly marked as C++0x only).

I'll post below an answer (struct inline initialization) as an example.

Note 1: Please, one answer per case. If you have multiple cases, please post multiple answers

Note 2: This is not a C question. Do not add the "C" tag to this question. This is not supposed to become a fight between C++ and C. Only the study of some constructs of the C subset of C++, and their alternative in other C++ "toolkits"

Note 3: This is not a C-bashing question. I want reasons. Boasting, bashing, and unproven comparisons will be downmodded. Mentioning C++ features without a C equivalent could be considered out of topic: I want the put side by side a C feature against a C++ feature.

+8  A: 

struct inline initialization vs. inline constructors

Sometimes, we need in C++ a simple aggregation of data. The data being somewhat independant, protecting it through encapsulation would not be worth the effort.

// C-like code in C++
struct CRect
{
   int x ;
   int y ;
} ;

void doSomething()
{
   CRect r0 ;               // uninitialized
   CRect r1 = { 25, 40 } ;  // vulnerable to some silent struct reordering,
                            // or adding a parameter
}

; I see three problems with the code above:

  • if the object is not specifically initialized, it won't be at initialized all
  • if we echange x or y (for whatever reason), the default C initialization in doSomething() will now be wrong
  • if we add a z member, and liked it to be "zero" by default, we would still need to change every inline initializing

The code below will have the constructors inlined (if really useful), and thus, will have a zero cost (as the C code above):

// C++
struct CRect
{
   CRect() : x(0), y(0) {} ;
   CRect(int X, int Y) : x(X), y(Y) {} ;
   int x ;
   int y ;
} ;

void doSomething()
{
   CRect r0 ;
   CRect r1(25, 40) ;
}

(The bonus is that we could add a operator== methods, but this bonus is out of topic, and so worth mentioning but not worth as an answer.)

Edit: C99 has named initialized

Adam Rosenfield made an interesting comment I find very interesting:

C99 allows named initializers: CRect r = { .x = 25, .y = 40 }

This won't compile in C++. I guess this should be added to C++, if only for C-compatibiliy. Anyway, in C, it alleviates the problem mentioned in this answer.

paercebal
C99 allows named initializers: CRect r = { .x = 25, .y = 40 };
Adam Rosenfield
Interesting point. This won't compile in C++ g++ ("error: expected primary-expression before ‘.’ token"), so this does not invalidate this whole post, but still a very good point worth knowing.
paercebal
Nope, it doesn't compile with g++, but if you're compiling _pure_ C code, it works with gcc. I've tested it with gcc 3.4.4, but I'm sure it works in plenty of other versions of gcc as well.
Adam Rosenfield
I don't see why inline initialisation is "vulnerable" to adding or re-ordeing members, but calling a constructor apparently isn't "vulnerable" to adding or re-ordering parameters. Either an interface is fixed or it isn't, and that applies to a struct as much as it does to a constructor.
Steve Jessop
Actually, I'll give you "adding a parameter", since if you add a parameter to the constructor, the code will stop compiling, whereas if you add a member to a struct then the leftovers are silently 0-inited. But they're equally vulnerable to re-ordering.
Steve Jessop
@onebyone: Take the two CRect structs, compile them, and see the result. Then invert the int x/int y declaration inside the struct. You'll see the C CRect is inverted, while the C++ CRect has still the correct result. [...]
paercebal
[...] The "interface" of the C++ CRect is the constructor (as long as the constructor is unchanged, everything's ok), while the interface of the C CRect is the struct itself (the moment it's changed, it won't work). The zero-cost inline C++ indirection given by the constructor changes everything.
paercebal
I agree with this post, but wanted to point out that adding a constructor to a struct will make it no longer a POD type. This is not the case in C++0x
michalmocny
@michalmocny: You're right, but the "POD" is a non issue on C++ (i.e. who cares?) unless you're playing with shared memory between processes, malloc-allocated memory or other pure-C-features. In this post, I was only mentionning C-style constructs against C++ constructs in pure C++ compiled code.
paercebal
A: 

Nearly any use of void*.

You should offer an example of C code at its maximum safety using void *, and the example of C++ code using whatever solution to offer the same solution. This would upmod your post.
paercebal
+25  A: 

Macros vs. inline templates

C style:

#define max(x,y) (x) > (y) ? (x) : (y)

C++ style

inline template<typename T>
const T& max(const T& x, const T& y)
{
   return x > y ? x : y;
}

Reason to prefer C++ approach:

  • Type safety -- Enforces that arguments must be of same type
  • Syntax errors in definition of max will point to the correct place, rather than where you call the macro
  • Can debug into the function
JohnMcG
In addition, the C++ version doesn't evaluate arguments twice. Consider max(++i, ++j): the C version will increment either i or j twice rather than once.
David Thornley
Perhaps a better version would be two "max" functions. One waiting for const reference parameters and returning the const reference of the max, the other waiting for non-const reference parameters, and returning the non-const reference of the max... But this is out topic ^_^ ... +1
paercebal
Max really isn't that simple, you really should read this http://www.ddj.com/cpp/184403774
Motti
Right -- I remember reading that when it came out -- my version also makes a copy, which is probably undesirable and I will edit to fix.
JohnMcG
Thanks for the link, Motti !
paercebal
The C version is wrong, dangerous, or both. I'll add the parentheses necessary to make it safe(r).
Konrad Rudolph
You've still got the C version wrong. parens around the entire expansion are needed as well.
Roddy
The C version may be dangerous, but I still use it in preference to "80 lines of template source code (plus the Loki library) which won't compile with any currently available compiler". (summary of motti's link)
Roddy
@Roddy: JohnMcG's solution, completed with the non-const version, is more than enough for most uses. I've yet to be bothered by std::min and std::max offered by the STL (use the one line "#include <algorithm>"), while a "#define max" macro already trashed a perfectly namespaced/encapsulated code.
paercebal
Of coutse, that the macro version is complicated to get right is part of the problem with it.
JohnMcG
Not withstanding that Macros have a 'scope' from `#define` to `#undef` or the end of the file. `template<>`s are scoped by namespaces, classes, functions, and blocks, just as other function and class names are.
Aaron
It took me a few tries, but i hope it's fine now: http://codepad.org/R6i0te8h . tries to work with const/nonconst parameters, and with them having different types (finds their common type by applying of operator ?: ) no loki or whatsoever needed. but maybe there is a bug i've overseen?
Johannes Schaub - litb
+13  A: 

Default parameters:

C:

void AddUser(LPCSTR lpcstrName, int iAge, const char *lpcstrAddress);
void AddUserByNameOnly(LPCSTR lpcstrName)
  {
  AddUser(lpcstrName, -1,NULL);
  }

C++ relpacement/equivalent:

void User::Add(LPCSTR lpcstrName, int iAge=-1, const char *lpcstrAddress=NULL);

Why it's an improvement:

Allows programmer to write express the function of the program in fewer lines of source code and in a more compact form. Also permits default values for unused parameters to be expressed closest to where they are actually used. For the caller, simplifies the interface to the class/struct.

Steve
I don't really like that use of overloaded functions. Yes, they all add info, but I don't think they should be one function that's overloaded.
Thomas Owens
I reformatted the post to have the code pretty-printed. Please Steve, could you edit your post to break it into two posts, and explain the pros/cons of each solution? (And change, perhaps, the LPCSTR into const char * for the non-Windows people?). I'm waiting for that to add a +1 to each post.
paercebal
@Thomas: I agree, even if it still depends on the context. While the example can be discussed, their comparison with the C code is what gives them their value in the current topic. I'm surprised no one mentionned the "abs" and "fabs" of C against a possible cpp::abs function.
paercebal
@paercebal. Thanks for the edit and the suggestions. I have done as you requested.
Steve
Default parameters are very useful, but one must be careful with them. I've seen them pretty badly abused ("magic" default values that drastically change the function's behaviour, for instance.)
Jonathan Grynspan
+29  A: 

RAII and all the ensuing glory vs. manual resource acquisition/release

In C:

Resource r;
r = Acquire(...);

... Code that uses r ...

Release(r);

where as examples, Resource could be a pointer to memory and Acquire/Release will allocate/free that memory, or it could be an open file descriptor where Acquire/Release will open/close that file.

This presents a number of problems:

  1. You might forget to call Release
  2. No information about the data flow for r is conveyed by the code. If r is acquired and released within the same scope, the code does not self-document this.
  3. During the time between Resource r and r.Acquire(...), r is actually accessible, despite being uninitialized. This is a source of bugs.

Applying the RAII methodology, in C++ we obtain

class ResourceRAII
{
  Resource rawResource;

  public:
  ResourceRAII(...) {rawResource = Acquire(...);}
  ~ResourceRAII() {Release(rawResource);}

  // Functions for manipulating the resource
};

...

{
  ResourceRAII r(...);

  ... Code that uses r ...
}

The C++ version will ensure you do not forget to release the resource (if you do, you have a memory leak, which is more easily detected by debugging tools). It forces the programmer to be explicit about how the resource's data flow (ie: if it only exists during a function's scope, this would be made clear by a construction of ResourceRAII on the stack). There is no point during between the creation of the resource object and its destruction where the resource is invalid.

Its also exception safe!

Andrew Top
I believe in your example, you need to adjust the constructor and destructor to be named ResourceRAII() and ~ResourceRAII(), as that is the name of the class.
Aaron
+1, RAII is the best C++ invention ever. I did not even found a single case where it was "over-used" (like e.g. a singleton pattern). Its just the best thing since sliced bread, and if would've been invented earlier, maybe nobody would've had to invent garbage collection ...
frunsi
+6  A: 

iostream vs stdio.h

In C:

#include <stdio.h>

int main()
{
    int num = 42;

    printf("%s%d%c", "Hello World\n", num, '\n');

    return 0;
}

The format string is parsed at runtime which means it is not type safe.

in C++:

#include <iostream>

int main()
{
    int num = 42;

    std::cout << "Hello World\n" << num << '\n';
}

The data types are known at compile time, and there's also less to type because there is not need for a format string.

da_code_monkey
Have you ever profiled stdio vs. iostream? I think you'll be surprised to find that stdio is significantly faster than iostream.
Adam Rosenfield
I agree. While this is interesting (sprintf is easy to abuse), iostreams are slow enough (i.e. 5 times stdio equivalent if my memory serves) to have Herb Sutter write an article on it. [...]
paercebal
[...] Thus, this answer is outside my "I need to read the reasons the C++ construct is as good as or even better the original C construct" requirement.
paercebal
printf (besides being faster) also is much easier to type in. All the closing and reopening quotes (for cout) really slows you down.
paperhorse
Yep. There's also the question of verbosity - setw, setprecision and friends versus the compact field width and precision modifiers for % conversions.
fizzer
"less to type" seems to be a spurious claim too, given that in the above example, the iostream code would be precisely the same number of characters, except that the "return 0" from main was left out...
Steve Jessop
The verbosity of iostream drives me mental and I refuse to use it in anything but the most trivial cases. To wit:printf("0x%08xn", x);vsstd::cout << std::hex << std::setfill('0') << std::setw(8) << x << std::dec << std::endl;
Rodyland
I agree with all the posts about iostream's verbosity. C++ iostreams are safer than any C counterpart (the result will always be Ok, i.e., no buffer overrun and no truncated string), but it is more verbose and slower. I guess this should be mentionned in the answer.
paercebal
(sn)printf is also better for i18n, at least with gettext, because the translator gets the whole string and not only some snippets of it. He can even reorder the values if needed.
quinmars
+15  A: 

Dynamic arrays vs. STL containers

C-style:

int **foo = new int*[n];
for (int x = 0; x < n; ++x) foo[x] = new int[m];
// (...)
for (int x = 0; x < n; ++x) delete[] foo[x];
delete[] foo;

C++-style:

std::vector< std::vector<int> > foo(n, std::vector<int>(m));
// (...)

Why STL containers are better:

  • They're resizeable, arrays have fixed size
  • They're exception safe - if unhandled exception occurs in (...) part, then array memory may leak - container is created on stack, so it will be destroyed properly during unwind
  • They implement bound checking, e.g. vector::at() (getting out of bounds on array will most likely generate an Access Violation and terminate the program)
  • They're easier to use, e.g. vector::clear() vs. manually clearing the array
  • They hide memory management details, making code more readable
PiotrLegnica
I guess there is no need for a 2D array. A 2D array for C++ could be broken (i.e. one line could be 5 items long, and the other could 7). Whereas a <code>char a[25][6]</code> is always Ok and fast. The same example with a 1D array vs. a vector would be better. Until we have N-dimension arrays in C++
paercebal
Note, too, that the access through vector::operator[] is as fast as the one one a C array through pointer arithmetics or [] use.
paercebal
P.S.: When I write "A 2D array for C++ could be broken", I write about an exposed vector of vector. A private vector of vector in a "Matrix" class would not be victim of this problem thanks to encapsulation. But this goes beyond the topic, I guess.
paercebal
+17  A: 

#define vs. const

I keep seeing code like this from developers who have coded C for a long time:

#define MYBUFSIZE 256

.  .  . 

char somestring[MYBUFSIZE];

etc. etc.

In C++ this would be better as:

const int MYBUFSIZE = 256;

char somestring[MYBUFSIZE];

Of course, better yet would be for a developer to use std::string instead of a char array but that's a separate issue.

The problems with C macros are legion--no type checking being the major issue in this case.

From what I've seen, this seems to be an extremely hard habit for C programmers converting to C++ to break.

Onorio Catenacci
This used to be awkward because compilers/linkers wouldn't let you place "const int X=100" in the .h file - you needed "extern const int X" in a header, and "const int x=100;" in a .c file, which was painful. Seems to work OK now, though.
Roddy
@Roddy : Today, this is ok for const expressions (I guess they will be inlined away)
paercebal
I've actually grown to like using enums for constants - works well in both C and C++. The only drawback is that you don't get to force a particular type, but that's rarely a concern.
Michael Burr
One big problem with macros like this is that they are global. What if two unrelated libraries define "BUFSIZE"?
Qwertie
@Qwertie : To be more clear, Macros have a 'scope' from `#define` to `#undef` or the end of the file. `const`s are scoped by namespaces, classes, functions, and blocks, just as variables.
Aaron
I like to use "static const int x = 100;" in the header files. Each translation unit will then technically have it's own copy of the constant, but as paercebal points out, you can expect it to be inlined away.
Boojum
In the Microsoft debugger, putting your cursor over the `const int` defined label will display the value, but not for labels using `#define`. This is enough reason for me to prefer it.
Mark Ransom
A: 

In the interests of balance, this post has an example of a C style construct which is sometimes better than the C++ style equivalent.

fizzer
Let me give it a try... ^_^ ...
paercebal
Please elaborate. I'm not disagreeing but it's not obvious.
Konrad Rudolph
See my second answer on this topic.
paercebal
C++ only allows constant-expressions as array dimensions. Apparently paercebal's compiler allows variable length arrays as an extension.
fizzer
You misunderstood my example: C++ allows templates to generate constant expression at compile time. The pointer was refused by the template, which is a good thing because we don't want the code to believe a pointer is a 4-item wide array (like the macro made us believe).
paercebal
The compiler is g++. This is not an extension. This is full, pure C++ templates, and work at least in Visual C++, too (the array_size code was inspired by Visual C++ strpcy_s code).
paercebal
The Standard is clear - see 5.19 Constant Expressions. If you don't have it, I'm sure an online draft will say the same. Your g++ will also reject the construct if you turn off extensions with the -pedantic flag.
fizzer
@Fizzer: You're right about the -pedantic part.
paercebal
@Fizzer: Still, it appears my code is valid under C++0x... ^_^
paercebal
Never mind - you're getting upvoted. Enjoy your karma.
fizzer
Note that this does not invalidate your point: There are situations when macros are THE solution. Andrei Alexandrescu used them a lot in his "Modern C++" book and C++ Loki library.
paercebal
C99 provides for VLA - variable-length arrays. The size of the array varies at runtime, depending on the call to the function. Note that in this case, sizeof() is no longer a compile-time constant.
Jonathan Leffler
+10  A: 

C's qsort function versus C++' sort function template. The latter offers type safety through templates which have obvious and less obvious consequences:

  • Type safety makes the code less error-prone.
  • The interface of sort is slightly easier (no need to specify the size of the elements).
  • The compiler knows the type of the comparer function. If, instead of a function pointer, the user passes a function object, sort will perform faster than qsort because inlining the comparison becomes trivial. This isn't the case with function pointers that are necessary in the C version.

The following example demonstrates the usage of qsort versus sort on a C-style array of int.

int pint_less_than(void const* pa, void const* pb) {
    return *static_cast<int const*>(pa) - *static_cast<int const*>(pb);
}

struct greater_than {
    bool operator ()(int a, int b) {
        return a > b;
    }
};

template <std::size_t Size>
void print(int (&arr)[Size]) {
    std::copy(arr, arr + Size, std::ostream_iterator<int>(std::cout, " "));
    std::cout << std::endl;
}

int main() {
    std::size_t const size = 5;
    int values[] = { 4, 3, 6, 8, 2 };

    { // qsort
        int arr[size];
        std::copy(values, values + size, arr);
        std::qsort(arr, size, sizeof(int), &pint_less_than);
        print(arr);
    }

    { // sort
        int arr[size];
        std::copy(values, values + size, arr);
        std::sort(arr, arr + size);
        print(arr);
    }

    { // sort with custom comparer
        int arr[size];
        std::copy(values, values + size, arr);
        std::sort(arr, arr + size, greater_than());
        print(arr);
    }
}
Konrad Rudolph
Please, could you add code as example: One use of qsort, and one use of std::sort?
paercebal
Note that Bjarne Stroustrup confirms Konrad's answer: http://www.research.att.com/~bs/bs_faq2.html#sort
paercebal
I believe I read somewhere C got better at inlining call to function through function pointers, but I have still to find that article. Anyway, the point is more than valid.
paercebal
+1 for the code. Thanks !
paercebal
+4  A: 

Following fizzer's post at http://stackoverflow.com/questions/226828/c-constructs-replacing-c-constructs#227310, I'll write here my answer:

Warning: The C++ solution proposed below is not standard C++, but is an extension to g++ and Visual C++, and is proposed as a standard for C++0x (Thanks to Fizzer's comments about this)

Note that Johannes Schaub - litb's answer offers another, C++03 compliant way to do it anyway.

Question

How to extract the size of a C array?

Proposed C solution

Source: http://stackoverflow.com/questions/96196/when-are-c-macros-beneficial#97292


#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])

Unlike the 'preferred' template solution discussed in a current thread, you can use it as a constant expression:

char src[23];
int dest[ARRAY_SIZE(src)];

I disagree with Fizzer as there is a templated solution able to generate a constant expression (In fact, a very interesting part of templates is their capacity to generate constant expressions at compilation)

Anyway, ARRAY_SIZE is a macro able to extract the size of a C array. I won't elaborate about the macros in C++: The aim is to find an equal or better C++ solution.

A better C++ solution?

The following C++ version has none of the macro problems, and can do anything the same way:

template <typename T, size_t size>
inline size_t array_size(T (&p)[size])
{
   // return sizeof(p)/sizeof(p[0]) ;
   return size ; // corrected after Konrad Rudolph's comment.
}

demonstration

As demonstrated by the following code:

#include <iostream>

// C-like macro
#define ARRAY_SIZE(arr) (sizeof arr / sizeof arr[0])

// C++ replacement
template <typename T, size_t size>
inline size_t array_size(T (&p)[size])
{
   // return sizeof(p)/sizeof(p[0]) ;
   return size ; // corrected after Konrad Rudolph's comment.
}

int main(int argc, char **argv)
{
   char src[23];
   char * src2 = new char[23] ;
   int dest[ARRAY_SIZE(src)];
   int dest2[array_size(src)];

   std::cout << "ARRAY_SIZE(src)  : " << ARRAY_SIZE(src) << std::endl ;
   std::cout << "array_size(src)  : " << array_size(src) << std::endl ;
   std::cout << "ARRAY_SIZE(src2) : " << ARRAY_SIZE(src2) << std::endl ;
   // The next line won't compile
   //std::cout << "array_size(src2) : " << array_size(src2) << std::endl ;

   return 0;
}

This will output:

ARRAY_SIZE(src)  : 23
array_size(src)  : 23
ARRAY_SIZE(src2) : 4

In the code above, the macro mistook a pointer for an array, and thus, returned a wrong value (4, instead of 23). The template, instead, refused to compile:

/main.cpp|539|error: no matching function for call to ‘array_size(char*&)’|

Thus demonstrating that the template solution is: * able to generate constant expression at compile time * able to stop the compilation if used in the wrong way

Conclusion

Thus, all in all, the arguments for the template is:

  • no macro-like pollution of code
  • can be hidden inside a namespace
  • can protect from wrong type evaluation (a pointer to memory is not an array)

Note: Thanks for Microsoft implementation of strcpy_s for C++... I knew this would serve me one day... ^_^

http://msdn.microsoft.com/en-us/library/td1esda9.aspx

Edit: The solution is an extension standardized for C++0x

Fizzer did rightly comment this was not valid in the current C++ standard, and was quite true (as I could verify on g++ with -pedantic option checked).

Still, not only this is usable today on two major compilers (i.e. Visual C++ and g++), but this was considered for C++0x, as proposed in the following drafts:

The only change for C++0x being probably something like:

inline template <typename T, size_t size>
constexpr size_t array_size(T (&p)[size])
{
   //return sizeof(p)/sizeof(p[0]) ;
   return size ; // corrected after Konrad Rudolph's comment.
}

(note the constexpr keyword)

Edit 2

Johannes Schaub - litb's answer offers another, C++03 compliant way to do it. I'll copy paste the source here for reference, but do visit his answer for a complete example (and upmod it!):

template<typename T, size_t N> char (& array_size(T(&)[N]) )[N];

Which is used as:

int p[] = { 1, 2, 3, 4, 5, 6 };
int u[sizeof array_size(p)]; // we get the size (6) at compile time.

Many neurons in my brain fried to make me understand the nature of array_size (hint: it's a function returning a reference to an array of N chars).

:-)

paercebal
http://www.csci.csusb.edu/dick/c++std/cd2/expr.html . See 5.19 Constant Expressions: 'functions ... shall not be used, and ... function-call ... operators shall not be used'
fizzer
Your link is about a "November 1996 Working Paper" draft: http://www.csci.csusb.edu/dick/c++std/cd2/ ... My own links are 2008 and are about C++0x
paercebal
I'm aware of that. The wording of the referenced paragraph is identical to the current standard.
fizzer
You're right. So I guess we all agree on the fact that today, the code above is an extention to C++ offered by g++ and Visual C++, and that the C++0x will most probably include something like that (i.e. using the constexpr keyword) for the next standard.
paercebal
No problem. Thanks for making the correction so prominently.
fizzer
@Fizzer: Thanks for your contribution. I learned I lot today, thanks to the discussion we shared.
paercebal
Er … why don't you simply return the `size` template argument in your function? The calculation of the size is completely redundant.
Konrad Rudolph
Good point. While this is not important (the calculation is done at compile time), I guess that Konrad is right and that the "size" parameter could be used directly. I'll verify this and correct the code.
paercebal
you can have a fully standard compliant constant expression by using this one. no need to wait for c++0x :) : template<typename T, size_t N> char ( int dest2[sizeof array_size(src)];
Johannes Schaub - litb
+4  A: 

casting the C way (type) versus static_cast<type>(). see there and there on stackoverflow for the topic

PW
You should make a summary, detailing with one sentence the exclusive use of each C++ cast, and finishing with something like "In C++, we can limit the cast's scope (const, static, etc.) and it's easier to find/grep in a large project".
paercebal
Right, but since you were the one who ask and that now I see that you are aware of those points on one hand. And, in the other hand, C++ cast are well covered by the ther two posts of which I provide links in my response, I think it's better to let the it concise. Anyhow thanks for the advice.
PW
+5  A: 

Local (automatic) variables declaration

In C, you must declare all local variables at the start of the block in which they are defined.

In C++ it is possible (and preferable) to postpone variable definition before it must be used. Later is preferable for two main reasons:

  1. It increases program clarity (as you see the type of variable where it is used for the first time).
  2. It improves program efficiency (as variables are constructed just when they actually needed).
Alex Che
It also produces small, cohesive nuggets of code that make editing/refactoring easier.
Steve Fallows
It also frequently delays variable declaration until the variable can be intelligently initialized. This is a reduction in exposure, and if the variable is not of a basic type can lead to performance improvements.
David Thornley
I find this feature provides much cleaner code. This feature makes functional decomposition much easier. So much so that in C I will wrap my variables in { } to trap them to the minimum of lines possible. It's even worth using tiny {} block in C++.
mat_geek
This is bogus - C99 (nearly a decade old now) provides C++-style declaration of variables at any point in a function. The number of people who use it, though, is limited.
Jonathan Leffler
A: 

Overloaded functions:

C:

AddUserName(int userid, NameInfo nameinfo);
AddUserAge(int userid, int iAge);
AddUserAddress(int userid, AddressInfo addressinfo);

C++ equivalent/replacement:

User::AddInfo(NameInfo nameinfo);
User::AddInfo(int iAge);
User::AddInfo(AddressInfo addressInfo);

Why it's an improvement:

Allows the programmer to express the interface such that the concept of the function is expressed in the name, and the parameter type is only expressed in the parameter itself. Allows the caller to interact with the class in a manner closer to an expression of the concepts. Also generally results in more concise, compact and readable source code.

Steve
While the pass-by-copy would probably be better as pass-by-const-reference, I've seen enough of this pattern to believe the non-use of overloaded function in stead really was a "I'm not comfortable with C++ overloaded functions" statement. +1. (Who the hell downmodded you anyway?)
paercebal
A: 

iostreams

Formatted I/O may be faster using the C runtime. But I don't believe that low-level I/O (read,write,etc.) is any slower with streams. The ability to read or write to a stream without caring if the other end is a file, string, socket or some user-defined object is incredibly useful.

Ferruccio
Do you have an example of code enabling a junior developer to compare the two versions?
paercebal
+1  A: 

In response to Alex Che, and in fairness to C:

In C99, the current ISO standard spec for C, variables may be declared anywhere in a block, the same as in C++. The following code is valid C99:

int main(void)
{
   for(int i = 0; i < 10; i++)
      ...

   int r = 0;
   return r;
}
chazomaticus
+2  A: 

I'll offer something that is perhaps abundantly obvious, Namespaces.

c's crowded global scope:

void PrintToScreen(const char *pBuffer);
void PrintToFile(const char *pBuffer);
void PrintToSocket(const char *pBuffer);
void PrintPrettyToScreen(const char *pBuffer);

vs.

c++'s definable subdivisions of global scope, namespaces:

namespace Screen
{
   void Print(const char *pBuffer);
}

namespace File
{
   void Print(const char *pBuffer);
}

namespace Socket
{
   void Print(const char *pBuffer);
}

namespace PrettyScreen
{
   void Print(const char *pBuffer);
}

This is a bit of a contrived example, but the ability to classify tokens you define into scopes that make sense prevents confusing purpose of the function with the context in which it is called.

Aaron
A: 

In c, much of your dynamic functionality is achieved by passing about function pointers. C++ allows you to have Function Objects, providing greater flexibility and safety. I'll present an example adapted from Stephen Dewhurst's excellent C++ Common Knowledge

C Function Pointers:

int fibonacci() {
  static int a0 = 0, a1 =1; // problematic....
  int temp = a0;
  a0 = a1;
  a1 = temp + a0;
  return temp;
}

void Graph( (int)(*func)(void) );
void Graph2( (int)(*func1)(void), (int)(*func2)(void) ); 

Graph(fibonacci);
Graph2(fibonacci,fibonacci);

You can see that, given the static variables in the function fibonacci(), the order of execution of Graph and Graph2() will change the behavior, not withstanding the fact that call to Graph2() may have unexpected results as each call to func1 and func2 will yield the next value in the series, not the next value in an individual instance of the series with respect to the function being called. (Obviously you could externalize the state of the function, but that would be missing the point, not to mention confusing to the user and complicating to the client functions)

C++ Function Objects:

class Fib {
  public:
    Fib() : a0_(1), a1_(1) {}
    int operator();
  private:
    int a0_, a1_;
};
int Fib::operator() {
    int temp = a0_;
    a0_ = a1_;
    a1_ = temp + a0_;
    return temp;
}


template <class FuncT>
void Graph( FuncT &func );

template <class FuncT>
void Graph2( FuncT &func1, FuncT &func2); 

Fib a,b,c;
Graph(a);
Graph2(b,c);

Here, the order of execution of the Graph() and Graph2() functions does not change the result of the call. Also, in the call to Graph2() b and c maintain separate state as they are used; each will generate the complete Fibonacci sequence individually.

Aaron
+1  A: 

Following paercebal's construct using variable length arrays to get around the limitation that functions can't return constant expressions yet, here is a way to do just that, in a certain other way:

template<typename T, size_t N> char (& array_size(T(&)[N]) )[N];

I've written it in some of my other answers, but it doesn't fit anywhere better than into this thread. Now, well, here is how one could use it:

void pass(int *q) {
    int n1 = sizeof(q); // oops, size of the pointer!
    int n2 = sizeof array_size(q); // error! q is not an array!
}

int main() {
    int p[] = { 1, 2, 3, 4, 5, 6 };
    int u[sizeof array_size(p)]; // we get the size at compile time.

    pass(p);
}

Advantage over sizeof

  1. Fails for non-arrays. Will not silently work for pointers
  2. Will tell in the code that the array-size is taken.
Johannes Schaub - litb
I've been reading and testing your code for 10 minutes, and I'm still wondering what in the hell is array_size (I'm not that good at parsing C++ types, I guess). Anyway, +1 for the gizmo (and for the time I'll spend trying to learn/understand it)
paercebal
Ok, I got it. It's the prototype of a function returning the reference to an array of N chars. The sizeof operator is used to get the size of the returned array of chars. I did not know the sizeof operator could be used on function prototypes to return the size of its returned type. Thanks!
paercebal
A: 

new in C++ vs malloc in C. (for memory management)

new operator allows class constructors to be called whereas malloc does not.

kal