32

As my first programming language I learned Java, but since I changed to a different University, I am now learning C++.

Coming from Java and learning the basics of C++, I read about references and reference variables. And how dangerous they can be, and how to be careful with them and so on.

So in my head arises one simple question: Why should I bother using that kind of complicated, and therefore potentially problem-causing, stuff at all?

Is it somehow worth it, or just a relic from times where RAM was about 64MB big?

Since a lot of answers have mentioned pointers: That concept is clearly from the stone age, imho. Except for high-performance-computation I wouldn't even touch that stuff.

Kevin
  • 53,822
  • 15
  • 101
  • 132
kwoebber
  • 425
  • 2
  • 5
  • 8
  • 9
    They're less dangerous than pointers. – Luchian Grigore Oct 04 '12 at 13:52
  • 6
    What you should ask yourself instead is: **Now that I got references, why do I need pointers?** (By the way, references and smart pointers are more like their Java counterparts than regular pointers). – Krumelur Oct 04 '12 at 13:53
  • 2
    Besides call by value, you had only references in java. – stacker Oct 04 '12 at 13:53
  • Can you give us an example of where you think a reference is a bad idea, while you think something else (and tell what) is better? – penelope Oct 04 '12 at 14:01
  • Software will always push the limits of memory. Try passing a `2000 x 2000 x 2000` volumetric MRI image by value. – japreiss Oct 04 '12 at 14:02
  • 4
    Trying to learn C++ through a filter of Java understanding is a bad idea. Try to forget everything you know about Java. You may not appreciate that Java is confusingly slipping in pointers when passing objects. In C++ everything is transparent. – TheMathemagician Oct 04 '12 at 14:06

8 Answers8

15

The problem is not related to references itself.

The problem is that in C++, object lifetime is managed differently than in Java or other run-time environments that use a garbage collector. C++ doesn't have standard built-in garbage collector. C++ object lifetime can be automatic (within local or global scope) or manual (explicitly allocated/deallocated in heap).

A C++ reference is just a simple alias for an object. It doesn't know anything about object lifetime (for the sake of efficiency). The programmer must care about it. An exception is the special case where a reference is bound to a temporary object; in this case, the lifetime of the temporary is extended to lifetime of the bound reference. Details are here.

References are an important part of C++ basic concepts and you just cannot avoid using them for 90% of tasks. Otherwise you have to use pointers, which is usually even worse :-)

E.g., when you need to pass object as function argument by reference instead of by value you can use references:

void f(A copyOfObj);       // Passed by value, f receives copy of passed A instance
void f(A& refToObj);       // Passed by ref, f receives passed A instance itself, modifiable
void f(const A& refToObj); // Passed by const ref, f receives passed A instance itself, non modifiable
Chad
  • 1,750
  • 2
  • 16
  • 32
Rost
  • 8,779
  • 28
  • 50
  • 1
    Is it more efficient to use references `rather` than `value`? – Ari Seyhun Sep 16 '17 at 19:50
  • 1
    @Acidi, in most cases yes. Passing object by value will lead to making object copy which can be costly in case of large objects and/or non-trivial object copy ctor/assignment operator. Passing object by reference will lead to copy pointer only. – Rost Sep 17 '17 at 20:16
  • Doesn't know about lifetime... unless it extends the lifetime. – rustyx Oct 27 '17 at 22:20
  • While I agree with @Rost, I'm not sure about the sentence "Passing object by reference will lead to copy pointer only". I believe mentioning a "pointer" here could be misleading, given the usual confusion with references and pointers. – Floella Apr 16 '20 at 13:28
11

If you pass large objects as function parameters by value, there could be a very real performance drop that is solved by passing them as references. Also, you can modify the objects inside functions if you pass them by reference instead of by value.

SurvivalMachine
  • 7,946
  • 15
  • 57
  • 87
  • 1
    Check out these? http://www.cplusplus.com/forum/beginner/3958/ http://stackoverflow.com/questions/377529/execution-speed-of-references-vs-pointers – Jeff Oct 04 '12 at 13:59
  • 1
    And http://cpp-next.com/archive/2009/08/want-speed-pass-by-value/ – ScaryAardvark Oct 04 '12 at 14:22
6

A reference is a pointer with restrictions. A reference is a way of accessing an object, but is not the object itself. If it makes sense for your code to use these restrictions, then using a reference instead of a pointer lets the compiler to warn you about accidentally violating them.

robrochta
  • 75
  • 5
  • I'm not sure a reference is a pointer of any kind... Given that a pointer is an object with its own memory address (separate from the memory address it stores) and a reference is not another variable but the same variable it refers to. Simply put: with pointers we have 2 objects/variables (the pointer itself and the pointed vaue) and with references there's just one, only identified by 2 different names. – Floella Apr 16 '20 at 13:32
6

As you just came from Java, I can imagine you have problems with a lot of dangerous stuff that C/C++ lets you do. In my opinion, the difference is here:

  • C/C++ lets you do a lot of powerful and dangerous stuff. You can do a lot of great things, but also shoot yourself in the leg
  • Java restricts what you can do in the name of safety

What you don't like ("pointers/references are dangerous") is exactly what I love ("it lets me do a lot of stuff, and if I mess up it's my fault") about C++. It's a matter of programming language taste, in my opinion.

References were made to avoid some dangers of pointers, but on the other hand, even the pointers still have uses besides the obvious fast-access stuff. For example, let's say that you have a low-level object that does some useful work and is shared between more than one high-level objects. It can be shared for various reasons (e.g. it updates the internal state every time it does useful work so copying it is not an option).

class HL{
    private:
    LL &object;

    public:
    HL(LL &obj){
        object = obj; // initialization of reference
    }
    // a no-argument constructor is not possible because you HAVE to
    // initialize the reference at object-creation (or you could initialize
    // it to a dummy static object of type LL, but that's a mess)
    void some_routine(){
        ....
        object.useful_work();
        ...
    }
}

Using references in this case enforces the initialization of internal object. If, on the other hand, the functionality that the object provides is just optional for the high-level object, than the pointer is a way to go:

class HL{
    private:
    LL *object;

    public:
    HL(LL &obj){
        object = &obj; // initialization of reference
    }
    HL(){} // no-argument constructor possible
    void some_routine(){
        ....
        if (object != NULL)
           object->useful_work();
        ...
    }
}

Also, as for use of the call-by-reference, that's the most useful when you're passing a big structure to a function, e.g. vector<int>.

void function(vector <int> a); // call by value, vector copied every time
void function(vector <int> &a); // call by reference, you can modify
                                // the vector in the function
void function(const vector <int> &a); // if you don't want to be able to modify
                                      // it, you can add const for "protection"
penelope
  • 8,251
  • 8
  • 45
  • 87
5

The most frequent use of references is to avoid an expensive deep copy; by default, C++ has value semantics, and if you write something like:

void f( std::vector<double> d );

The entire vector will be copied each time you invoke f. So you write something like:

void f( std::vector<double> const& d );

One place where this is particularly important is when defining a copy constructor. If you were to write:

MyType( MyType other );

, you would end up with infinite recursion since the compiler would have to call the copy constructor in order to copy the argument to this constructor. (In fact, the compiler will only accept a constructor which takes a reference to the copy constructor, precisely to avoid this problem.)

Outside of constructors, this is really an optimization and could be considered as premature optimization. In practice, however, the almost universal convention is to pass class types by reference to const, rather than by value.

References may also be used as out parameters; compared to a pointer, they have the advantage that they cannot be null.

References can also be used to provide a "window" into the class data. The classical example is the overload of operator[] in std::vector; it returns a reference so that you can modify, take the address of, etc. the actual element in the array.

Other than as parameters and return values, in the above cases, references are somewhat rare. If you use one as a class member, for example, you must be aware that you cannot give the class classical assignment semantics. (This is not an issue if the class doesn't support assignment.) As a global variable, they might be used to hide the implementation of what is being referred to, but this is exceedingly rare. As a local variable, about the only use I know, is to cache the results of another expression which returns a reference: for example, if I'm accessing someMap[aKey] a large number of times in a short block of code, it makes sense to write:

ValueType& element = someMap[aKey];

at the start, and use element after that. (Note that this only makes sense because someMap[aKey] returns a reference.)

Mihail Stancescu
  • 4,088
  • 1
  • 16
  • 21
James Kanze
  • 150,581
  • 18
  • 184
  • 329
3

The actual question is "why use references instead of pointers".

I haven't quite figured that out yet. Currently, I use references

  • because you can't assign to them. Worst case this doesn't mean anything to the compiler, but there's the chance that the compiler can make use of that knowledge.

  • often when I want to return a pointer that always exists, or to indicate that a parameter is required and may not be a nullptr (there is no null-reference). It's not a hard rule; sometimes an actual pointer feels more natural.

  • when things just ask for references, like operator overloads.

In general, I end up using a lot of references, since I don't generally want to copy objects unless I really need an actual copy, and references often work.

Christian Stieber
  • 9,954
  • 24
  • 23
2

References make call-by-reference easier, since the caller does not have to use the & operator when passinng an object.

Like this:

MyObject ob;

void foo_ref(MyObject& o){ ...}
void foo_ptr(Myobject* o){ ...}

//call

foo_ref(ob);
foo_ptr(&ob);

Furthermore, they enable initializing pointers in a function:

MyObject* ob = nullptr;
MySubject* sub = nullptr;

void foo_init(MyObject *& o, MySubject *& s) {

   o = new MyObject;
   s = new MySubject;
}

//call

foo_init(ob, sub);

Without the reference to pointer this example would only work with a pointers to pointers, making the code look terrible, as you would have to derefernce each argument first

MyObject* ob = nullptr;
MySubject* sub = nullptr;

void foo_init(MyObject ** o, MySubject ** s) {

   *o = new MyObject;
   *s = new MySubject;
}

//call

foo_init(&ob, &sub);
TeaOverflow
  • 2,468
  • 3
  • 28
  • 40
  • References make call by reference possible, because you cannot take the address of an arbitrary object to pass it to a function. – James Kanze Oct 04 '12 at 14:21
0

For example because they are forcing you to initialze, this makes them less dangerous

ISTB
  • 1,799
  • 3
  • 22
  • 31