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

C++

C++ Problem Overview


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

C++ Solutions


Solution 1 - C++

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

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

Solution 3 - C++

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.

Solution 4 - C++

I really don't understand why you got to all this trouble:

std::map < std::string, std::vector<std::string> > adjacencyMap;
std::vector<std::string>& sFriends = adjacencyMap["s"];
sFriends.push_back("a");
sFriends.push_back("v");
sFriends.push_back("g");

Why do you meddle with shared_ptr here ? The situation certainly does not call for it!

Solution 5 - C++

You can browse http://www.cplusplus.com/forum/beginner/3958/ for some insights. Also useful: http://www.velocityreviews.com/forums/t284603-pointers-vs-references-a-question-on-style.html

I guess there is no "right" answer. You need to weight pros and cons of each approach taking into account the specific context of your project.

I personally prefer references, but I recommend anyways to read those posts and muse about it.

Solution 6 - C++

As a general rule of thumb, always try to pass parameters by reference to const. Passing pointers can lead to ownership issues as well as a bunch of other possibilities for subtle mistakes.

What is the purpose of NULL? To indicate an invalid pointer/object. If you're going to pass invalid objects to a function, then all you have to do is have a method for checking an object's validity. As in:

void myfunc(const obj& myobj)
{
  if(myobj.valid())
    // DO SOMETHING
}

Primitive types you'd usually want to pass-by-value anyway, since there's such little overhead. And that's when you'd use literals most of the time anyway. For strings, you should try to use std::string and stay away from const char* C-style strings as much as you can. Of course if you have to use C-strings, then you have no choice but to use pointers, but all in all references should be the way to go.

Oh and to be truly exception-safe try to avoid this:

vector<string>* myFriends = new vector<string>();
...
adjacencyMap["s"] = shared_ptr<vector<string> >(myFriends);

Instead do:

shared_ptr<vector<string> > myFriends(new vector<string>());

Look in to RAII and exception safety for why this is the preferred method.

Solution 7 - C++

Probably not an answer to the question. Just KISS.

int main()
{
        multimap<string, string> adjacencyMap;
        adjacencyMap.insert(std::make_pair("s", "a"));
        adjacencyMap.insert(std::make_pair("s", "v"));
        adjacencyMap.insert(std::make_pair("s", "g"));
        return 0;
}

Solution 8 - C++

I would prefer

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

as this ensures your local var handling is exception-safe.

I don't really see how this addresses your q which was about the merits of ref vs ptr, though. In both of the examples you cite I would expect to use the second (ref) form.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionuser855View Question on Stackoverflow
Solution 1 - C++David ThornleyView Answer on Stackoverflow
Solution 2 - C++LucasView Answer on Stackoverflow
Solution 3 - C++user180326View Answer on Stackoverflow
Solution 4 - C++Matthieu M.View Answer on Stackoverflow
Solution 5 - C++SebastianView Answer on Stackoverflow
Solution 6 - C++ZoliView Answer on Stackoverflow
Solution 7 - C++ronagView Answer on Stackoverflow
Solution 8 - C++Steve TownsendView Answer on Stackoverflow