When to pass by reference and when to pass by pointer in C++?

Common Situations:

  1. Passing std::string to a function foo(std::string*) or foo(std::string&);
  2. Passing tr1::shared_ptr to a function foo(tr1::shared_ptr* ptr) or foo(tr1::shared_ptr& ptr);

In general, what is a good practice. I always get confused. At first, passing everything as references seems consistent, however it is not possible to pass in Literals as references or NULLs as references.

Similarly, having everything as pointers seems good, but having then I have to worry that pointers might be pointing to NULL and check for those conditions in the beginning of that function.

Do you think the following snippet is good?

#include <iostream>
#include <vector>
#include <map>
#include <string>
#include <tr1/memory>
#include <algorithm>
using namespace std;
using namespace std::tr1;

int main(){
        map<string, shared_ptr<vector<string> > > adjacencyMap;
        vector<string>* myFriends = new vector<string>();
        myFriends->push_back(string("a"));
        myFriends->push_back(string("v"));
        myFriends->push_back(string("g"));
        adjacencyMap["s"] = shared_ptr<vector<string> >(myFriends);
        return 0;
}

Thanks Ajay


Solution 1:

References are easier to get right.

Is your problem with literals that you aren't using const references? You can't bind a temporary (produced by a literal) to a non-const reference, because it makes no sense to change one. You can bind one to a const reference.

In particular, when passing an argument to a function, and the function isn't going to change it, and it isn't a built-in type, pass by const reference. It works much the same as pass by value, except it doesn't require a copy constructor call.

Pointers are useful in that they have a guaranteed invalid value you can test for. Sometimes this is irrelevant, and sometimes it's very important. Of course, you can't generally pass a literal by pointer, unless (in case of a string literal) it already is.

Some coding standards say that nothing should ever be passed by non-const reference, since it provides no indication at the point of call that the argument might be changed by the function. In that case, you will be required to pass by pointer. I don't favor this, particularly as programming tools make it easier and easier to get the function signature, so you can see if a function might change an argument. However, when working in a group or for an enterprise, style consistency is more important than any individual style element.

Solution 2:

A good rule of thumb: "Use references when you can and pointers when you have to".

Solution 3:

In my previous job, we had the the rule that plain references were practically never used. Instead we agreed to:

  • pass by value (for cheap to copy objects, all primitives, small value types, std::string, very small or refcounted strings)
  • pass by const reference (for readonly access to large objects)
  • pass by pointer if you need read-write access

If everybody follows these rules, you can assume that parameters passed to functions are not modified unless their adress was taken. It worked for us.