Parameters Semantics on C++

Parameters Semantics on C

In C, everything is passed by value. "primitives" and "PODs" are passed by copying their value. Modify them in your function, and the original won't be modified. Still, the cost of copying some PODs could be non-trivial.

When you use the pointer notation (the * ), you're not passing by reference. You're passing a copy of the address. Which is more or less the same, with but one subtle difference:

typedef struct { int value ; } P ;


void doSomethingElse(P * p)
{
   p
->value = 32 ;
   p
= malloc(sizeof(P)) ;
   p
->value = 45 ;
}

void doSomething()
{
   P
* p = malloc(sizeof(P)) ;
   p
->value = 25 ;

   doSomethingElse
(p) ;

     
int i = p->value ;
   

}

The final value of p->value is 32. Because p was passed by copying the value of the address. So the original p was not modified (and the new one was leaked).

Parameters Semantics on Java and C Sharp

It can be surprising for some, but in Java, everything is copied by value, too. The C example above would give exactly the same results in Java. This is almost what you want, but you would not be able to pass primitive "by reference/pointer" as easily as in C.

In C#, they added the "ref" keyword. It works more or less like the reference in C++. The point is, on C#, you have to mention it both on the function declaration, and on each and every call. I guess this is not what you want, again.

Parameters Semantics on C++

In C++, almost everything is passed by copying the value. When you're using nothing but the type of the symbol, you're copying the symbol (like it is done in C). This is why, when you're using the *, you're passing a copy of the address of the symbol.

But when you're using the &, then assume you are passing the real object (be it struct, int, pointer, whatever): The reference.

It is easy to mistake it as syntaxic sugar (i.e., behind the scenes, it works like a pointer, and the generated code is the same used for a pointer). But...

The truth is that the reference is more than syntaxic sugar.

  • Unlike pointers, it authorizes manipulating the object as if on stack.
  • Unline pointers, when associatied with the const keyword, it authorizes implicit promotion from one type to another (through constructors, mainly).
  • Unlike pointers, the symbol is not supposed to be NULL/invalid.
  • Unlike the "by-copy", you are not spending useless time copying the object
  • Unlike the "by-copy", you can use it as an [out] parameter
  • Unlike the "by-copy", you can use the full range of OOP in C++ (i.e. you pass a full object to a function waiting an interface).

So, references has the best of both worlds.

Let's see the C example, but with a C++ variation on the doSomethingElse function:

struct P { int value ; } ;

// p is a reference to a pointer to P
void doSomethingElse(P * & p)
{
   p
->value = 32 ;
   p
= (P *) malloc(sizeof(P)) ; // Don't bother with the leak
   p
->value = 45 ;
}

void doSomething()
{
   P
* p = (P *) malloc(sizeof(P)) ;
   p
->value = 25 ;

   doSomethingElse
(p) ;

     
int i = p->value ;
   
// Value of p ? 25 ? 32 ? 42 ?
}

The result is 42, and the old p was leaked, replaced by the new p. Because, unlike C code, we're not passing a copy of the pointer, but the reference to the pointer, that is, the pointer itself.

When working with C++, the above example must be cristal clear. If it is not, then you're missing something.

Conclusion

C++ is pass-by-copy/value because it is the way everything works, be it in C, in C# or in Java (even in JavaScript... :-p ...). And like C#, C++ has a reference operator/keyword, as a bonus.

posted @ 2011-11-02 22:00  Thomas Hwang  阅读(118)  评论(0编辑  收藏  举报