When you write your function signatures, you have a choice between passing values, pointers or references. You might be able to make any of them work for the compiler, but what do they tell the user?
Note that even though pointers and reference are somewhat related, and mostly communicate the same thing, they have different suggestions about ownership.
Parameters
1: Pass by value
void foo(Bar b);
I need to copy your object, because I need to modify it, and you don’t want to see the change. (Except for built-in types, which are usually passed by value even though they are not modified by the function.)
2: Pass by reference/pointer
void foo(Bar& b); void foo(Bar* b);
I need a reference to your object, in order to modify it, beacuse you need to see the change.
3: Pass by reference to const
void foo(const Bar& b); void foo(const Bar * b);
I won’t need to modify your object, and I don’t want to pay the price of a copy.
You could argue that 1 just means I will leave your object alone, and doesn’t say anything about modification. But if you aren’t going to modify it, you should use 3, so I think 1 explicitly states that the object is going to be modified (invisibly to the caller). Unless of course the argument is a built-in type.
Return values
1: Return by value
Bar foo();
Here, take this object and do whatever you want with it, I won’t touch it again. It’s yours.
2: Return a reference
Bar& foo();
There is an object over here that you can use. Someone else might silently change it, though. By the way, I own it, and it is my responsibility to delete it. (If foo()
is a non-static member function, you can usually assume that won’t happen until the object on which it is called goes out of scope. If foo()
is a static function, you can usually assume this won’t happen until the program exits.)
3: Return a pointer
Bar* foo();
There is an object over here that you can use. Someone else might silently change it, though. By the way, I might delete it at any time. Or maybe that’s your responsibility, and if you don’t, you’ll have a memory leak. But I won’t tell you which one it is! You need more information to be sure, for instance the documentation. Often, you can also deduce ownership from the situation. A singleton retains ownership, a factory does not.
4: Return a reference/pointer to const
const Bar& foo(); const Bar* foo();
There is an object over here that you can use, and I promise it won’t change, even if I still own it. Rules of deletion are as in 2. The reason I don’t list the ownership issues for the pointer in this case, is that I think const
is an indication that ownership is retained. If it was not, why use const
at all?
One thought on “Show Me Your Signature, and I’ll Tell You Who You Are”