20

I am brand new to C++. We have recently begun exploring reference variables in class, and I am very confused about them. Not necessarily how to do them, as I understand that they switch variable values, but more along the lines of WHY a developer would want to do such a thing? What do they accomplish? Do they save memory? Do they avoid having to return information?

Here is part of the project we are working on. We need to include at least one reference variable. I can see how I would write the program without the reference variable, but I don't see where a reference variable would be useful or necessary.

"The user may wish to get an estimate for one to many rooms. The rates are based on the square footage of the walls and/or ceiling. The company estimates that it takes 2.5 hours to paint 200 SF of wall space and 3.2 hours to paint the same area on a ceiling. The labor rate is $40 per hour. If the job for painting WALLS totals more than 1400 SF of space, then the customer receives a 15% discount for all square footage above 1400 square feet. There is no discount for painting ceilings.

The program shall print out a final report of the estimated costs in a professional format.

The program shall ask the user if they want to make more calculations before exiting."

I'm not looking for you guys to do my homework for me, and for reference, we have only just finished with learning functions. I'm pretty good, but there are a LOT of things reading through these sites that I do not understand.

And, essentially, studentID would be set to 21654. Am I understanding this correctly?

Let us try this again:

I have reviewed this suggested duplication. While it does cover the basics of the pros/cons of using reference variables instead of pointers and discusses multitudes of reasons for using both, I am still questioning the basic idea of when (when is is appropriate vs. not necessary) and why (why is appropriate in certain circumstances, what advantages does it give to the program?)

I should use such variables as well as how (the actual syntax and placement). Almost everyone here has been great, and I have learned so much on the subject through my interactions with you. Even as much of this is repetitive and irritating to seasoned coders, it is all new to me, and I needed to be involved in the conversation as much as I needed the information. I have used Stack Overflow for many projects, learning about Java's newString.equalsIgnoreCase(), for instance, and I admire your knowledge. I can only tell you the truth, if that is not good enough then it is what it is.

Alright, let me review my understanding so far:

Reference variables tend to cut down on unwanted modification of variables within a function and/or program.

Reference variables are used to modify existing variables within functions

This is useful as it "moves" values around while minimizing copying of those values.

Reference variables modify existing variables within functions/programs

I don't know if you guys can still read this or not since it has been flagged a duplicate. I've been playing with a few of the mini-programs you guys have given me, re-read portions of my book, done further research, etc., and I think I understand on a rudimentary level. These reference variables allow you to alter and/or use other variables within your code without pulling them directly into your code. I can't remember which user was using the foo(hubble, bubble) example, but it was his/her code that finally made it click. Instead of just using the value, you are actually using and/or reassigning the variable.

Community
  • 1
  • 1
Eryn
  • 235
  • 2
  • 8
  • 10
    The simplest and one of the most useful use-cases is passing large objects as arguments to functions without copying. Lets say you have a `std::vector` with millions of elements. If you pass that by value to a function, then all those elements needs to be copied. If you pass it *by reference* no copying is done. There's other use-cases too of course, but in most cases it boils down to "I don't need the full instance of the object, just a reference to it". – Some programmer dude Oct 27 '17 at 06:48
  • 1
    There are many good uses for reference variables, even beyond avoiding return values. – user0042 Oct 27 '17 at 06:50
  • 1
    Oh, and it's one of the two only ways to do *polymorphism* with inheritance. – Some programmer dude Oct 27 '17 at 06:50
  • 3
    Your examples are not valid syntax. `double studentID&` isn't a type. `double foo(double& y)` (or `double foo(studentID& y)` if `studentID` is a type). – Mat Oct 27 '17 at 08:23
  • Have you searched? This is a fundamental feature of the language, so it's not like examples or rationales are in short supply. Any good basic reference material should provide plenty. And there are already threads about this anyway, so I don't see why we need another. e.g.: [C++: Why do you need references when you have pointers?](https://stackoverflow.com/questions/10781661/c-why-do-you-need-references-when-you-have-pointers) / [Why should I use reference variables at all?](https://stackoverflow.com/questions/12728794/why-should-i-use-reference-variables-at-all) – underscore_d Oct 27 '17 at 10:01
  • 1
    I looked specifically for reference variables, not pointers. I was not aware of the connection until after asking this question. The reference variable questions/answers did not meet my needs, unfortunately, which is why I decided to ask my version of the question. – Eryn Oct 27 '17 at 10:04
  • I can't ascertain what your question is, as you seem to have multiple vague uncertainties, none of which strike me as being useful for discussion, as they appear to be just fundamental aspects of the language that you haven't come across in your book yet. I am baffled by the upvotes here. – underscore_d Oct 27 '17 at 10:30
  • 1
    When someone proposes a duplicate that you don't believe answers your question, it's not useful to just say it doesn't meet your needs, you need to explain why and/or edit and rephrase your question so we can see why you think that and we can answer your actual question as opposed to wasting everyone's time by just saying what's already been said in the duplicate. – Bernhard Barker Oct 27 '17 at 10:42
  • @Dukeling Unfortunately, my problem is vague. I'm sorry that my explanation of my needs isn't helpful, but that is part of why I am posing these questions. After reviewing the proposed duplication, I had no better understanding of the topic then I did before and thus I can only assume it did not meet my needs. I have found the answers in this question, and my participation in the discussion, to be very helpful thus far. I am very new to C++, so please, be kind and know I do not intend to "waste your time". I would have thought teaching/learning from others wasn't a waste? – Eryn Oct 27 '17 at 11:39
  • @Eryn I mean, if someone just says something similar to what's been said in the duplicate, it presumably won't answer your question or be helpful to you, thus time will have been wasted writing and reading the answer. – Bernhard Barker Oct 27 '17 at 12:07
  • @Dukeling I do understand. But, they are willing to write it. I hope that if they weren't, they wouldn't waste their time. Sometimes seeing the answer they have given before in a different context is helpful. I am trying to be as clear as I am able and the more we talk about this, the clearer I am able to be. Thank you for your input on the subject. It really is helpful. – Eryn Oct 27 '17 at 12:13
  • I don't get the point of your "follow up question". Why would you pass a parameter `a` into `foo` where the first thing `foo` does is set `a = 0`? You would get the same effect by declaring the function `int foo()`, and save the caller the wasted effort of passing in two values that are not going to have any effect on what the function does. (Of course then inside the function you will have `int a = 0;` instead of `a = 0;`.) – David K Oct 27 '17 at 12:58
  • SO is best for specific problems and solutions. Questions that only reflect someone trying to get to grips with general and/or fundamental concepts of a language do not generally make for useful, focussed threads that are of use to future readers - which is ultimately the point. As much as it's good if SO can help you understand things, ultimately it's not about any of us as individuals asking questions; it's about providing a source of useful discussions for future readers, too. The general/fundamental stuff is far better served by reading reference material & coding examples until you get it – underscore_d Oct 27 '17 at 12:58
  • 2
    In this case there are so many misunderstandings evident in your question and examples that it's hard to know which ones to try to address first. When you have more practice with the language you will probably work a lot of these out for yourself; you may be able then to understand the answers of the duplicate question, or if not, at least to ask a much better question of your own. – David K Oct 27 '17 at 13:03
  • @underscore_d Unfortunately, it isn't for me. I'm much better at grasping context when discussing or using them than I am just reading or regurgitating coding examples. I have to play with it, feel it and see it work and most of the time, I'm able to do this on my own. And I must disagree with your ascertain that "someone trying to get to grips with general/fundamental concepts of of a language do not generally make for useful, focused threads that are of use to future readers" as I have read MANY of these threads, some are general and fundamental and have served me well on many occasions. – Eryn Oct 27 '17 at 13:06
  • @DavidK I can agree with that. Perhaps that is what I'm struggling with. I'm not understanding what is said in one, so I'm trying to get a clearer understanding here? I'm just wondering, however: Did I accidentally wander into a no newbie zone? (Not being sarcastic, seriously asking). – Eryn Oct 27 '17 at 13:08
  • Newbie questions are fine; the "already answered" question is one of them. It just seems increasingly unlikely that further exposition here will help you at this time. – David K Oct 27 '17 at 17:21

10 Answers10

22

A reference variable is nothing but an alias name of the variable. You would use it when you wanted to just pass the value around instead of copying the same variable into memory at a different location. So, using reference, copy can be avoidable which saves the memory.

According to Bjarne Stroustrup's FAQ:

C++ inherited pointers from C, so I couldn't remove them without causing serious compatibility problems. References are useful for several things, but the direct reason I introduced them in C++ was to support operator overloading. For example:

void f1(const complex* x, const complex* y)    // without references
    {
        complex z = *x+*y;    // ugly
        // ...
    }

    void f2(const complex& x, const complex& y)    // with references
    {
        complex z = x+y;    // better
        // ...
    }

More generally, if you want to have both the functionality of pointers and the functionality of references, you need either two different types (as in C++) or two different sets of operations on a single type. For example, with a single type you need both an operation to assign to the object referred to and an operation to assign to the reference/pointer. This can be done using separate operators (as in Simula). For example:

Ref<My_type> r :- new My_type;
r := 7;            // assign to object
r :- new My_type;    // assign to reference

Alternatively, you could rely on type checking (overloading). For example:

Ref<My_type> r = new My_type;
r = 7;            // assign to object
r = new My_type;    // assign to reference

Also, read this Stack Overflow question about the differences between a pointer variable and a reference variable.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
msc
  • 33,420
  • 29
  • 119
  • 214
  • Alright, I just read the link you included. Something I believe I have figured out: You define a pointer with a *, such as in the link with *p. You can use this pointer several different times throughout the program, whereas a reference variable can only be used once. Question: can you use the reference variable as is, such as &numberOfSwings, anywhere in the program? Or is it restricted via scope? – Eryn Oct 27 '17 at 07:18
  • 1
    @Eryn References are nothing but constant pointers. So, It works exactly as for pointers. https://stackoverflow.com/questions/7603833/what-happens-in-c-when-i-pass-an-object-by-reference-and-it-goes-out-of-scope – msc Oct 27 '17 at 07:29
  • Wait a minute... I think I see something, please let me know if I'm getting this right or not: When you write complex* x or complex* y, you are creating two instances of the variable complex with differing pointers that hold different values and those pointers are how you refer to those differing (overloaded) variables instead of the variable names themselves? – Eryn Oct 27 '17 at 07:31
  • 1
    I'm sorry, but you just need to go back to the basics. In `complex* x`, `complex` is the type of the pointed-to object and `x` is a variable identifier. And a pointer is the value of an address in memory, at which a given type of object (maybe) resides. If you don't understand these yet, the place to be is in your book - or a better one - and not asking on SO. – underscore_d Oct 27 '17 at 10:29
  • 1
    Might be worth mentioning that RAII can often make it _necesarry_ to avoid copies when types have deleted their copy constructors. – gntskn Oct 27 '17 at 10:44
  • @underscore_d I did realize that when another user began using the object type "Room" in another answer. Thank you for pointing that out. – Eryn Oct 27 '17 at 11:53
12

I will give three reasons, but there are many more.

  1. Avoiding unnecessary copies.

    Suppose you write a function like so:

    double price(std::vector<Room> rooms)
    {
           ...
    }
    

    Now, every time you call it, the vector of Room will be copied. If you only compute the prices of a few rooms that's fine, but if you want to compute the cost of repainting the entirety of the offices of the Empire State Building, you will start to copy huge objects, and this takes time.

    It is better in this case to use a constant reference that provides read-only access to the data:

    double price(const std::vector<Room>& rooms) { ... }
    
  2. Using polymorphism

    Suppose you now have different types of rooms, perhaps a CubicRoom and a CylindricalRoom, that both inherit from the same base class, Room.

    It is not possible to write:

    double price(Room room) { ... }
    

    and then call

    price(CylindricalRoom());
    //or
    price(CubicRoom());
    

    but you can if you define price as follows:

    double price(Room& room);
    

    Everything then works the same as if you passed by value.

  3. Avoiding returns

    Suppose that each time you compute a price, you want to add a formatted quote to a report. In C++ you can only return a single object from a function, so you can not write:

    return price, fmtQuote
    

    However, you can do:

    double price(Room room, std::vector<std::string>& quotes)
    {
        ...
        quotes.push_back(fmtQuote);
        return price
    }
    

    Obviously, you could return a pair of objects std::pair<double, std::string>, but this means that the caller has to unpack the result. If you intend to call often the above function, this will quickly become ugly. In this case, this ties in to the first point: the log of all quotes will grow, and you do not want to copy it for each call.

    This is a typical access pattern for shared resources: you want a few functions/objects to get a handle on a resource, not a copy of that resource.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Urukann
  • 475
  • 4
  • 10
  • 3
    You can't pass an rvalue to a function which takes a non-const reference as a parameter, const needs to be added: `double price(const Room& room);`. Otherwise nice, clear answer +1 :) – AzCopey Oct 27 '17 at 09:04
  • Unpacking result is easy in C++17: `auto[price, quote] = price(CircularRoom());`, and is recommended by CppCoreGuidelines, specifically [F.21](http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#Rf-out-multi) – Erbureth Oct 27 '17 at 09:56
  • It **is** possible to pass subclasses as a value of the base in point 2, but it just won't do what most users will expect or want, due to object slicing. – underscore_d Oct 27 '17 at 11:26
10

You're mixing up two completely separate things here. Three examples to show how the two things work, individually and then together...

  1. A function can take a parameter passed by value, and return a value.

    double foo (double y)
    {
        y = y + 200.0;
        return y;
    }
    
    void main(void)
    {
        double hubble = 50.0;
        double bubble = 100.0;
    
        hubble = foo(bubble);
    
        std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl;
    }
    

    Note that because this is passed by value, even though foo() changes y, bubble does not change. hubble is set to the value returned by foo().

    Then you get

    hubble=300, bubble=100
    
  2. A function can take a parameter passed by reference, and modify that parameter.

    void foo (double& y)
    {
        y = y + 200.0;
    }
    
    void main(void)
    {
        double hubble = 50.0;
        double bubble = 100.0;
    
        foo(bubble);
    
        std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl;
    }
    

    Then you get

    hubble=50, bubble=300
    

    Of course hubble hasn't changed. But because bubble was passed by reference, the change to y inside foo() changes bubble, because that change is happening on the actual variable passed and not on a copied value.

    Note that you do not have a "return" statement here. The function does not return anything - it simply modifies the variable which is passed to it.

  3. And of course you can use both together.

    double foo (double& y)
    {
        y = y + 200.0;
        return y + 400.0;
    }
    
    void main(void)
    {
        double hubble = 50.0;
        double bubble = 100.0;
    
        hubble = foo(bubble);
    
        std::cout << "hubble=" << hubble << ", bubble=" << bubble << std::endl;
    }
    

    Then you get

    hubble=700, bubble=300
    

    As before, changing y inside foo() changes bubble. But now the function is returning a value as well, which sets hubble.

Why would you choose to return a value, or to modify the value passed in, or to do both? That entirely depends on how you write your code.

I agree with you that you don't have to use a pass-by-reference here. Myself, I'd probably just return a value. But this is a learning exercise, and you've been told to do it that way, so you've got to. Suppose your pass-by-reference is the discount? So a function "void discount(double& value)" takes the value passed and multiplies it by 0.85. It's a bit artificial, but it would demonstrate the principle.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Graham
  • 1,655
  • 9
  • 19
  • Thank you. This was very easy to follow. Please forgive my mixup, I was very tire when writing the edit. So, in a reference variable, you are declaring a variable type and the reference itself. This means that any parameter you enter into the function is now equal to the reference variable or modifies it. If y, for instance, had been set to 50.0 and bubble was 100.00 and you simply had a cout in foo that read cout << "bubble is " + bubble; the result would be "bubble is 100" instead of 50? – Eryn Oct 27 '17 at 10:00
  • @Eryn If you added a line `std::cout << "value is " << y << std::endl;` at the start of foo(), before y is modified, then the result would show `value is 100`. You couldn't do `std::cout << "value is " << bubble << std::endl;` within foo(), because foo() doesn't know about a variable called bubble. It only knows about a variable called y. In the second and third examples, the main() function passes bubble by reference, so bubble and y are the same thing - but foo() doesn't know that. This is what's called the *scope* of the variable: who knows about which variable names. – Graham Oct 27 '17 at 10:47
  • @Eryn As a little side-note, idiomatic C/C++ would be to write `y += 200.0;` instead of `y = y + 200.0;`. I deliberately didn't do that in the examples, in case you hadn't met the "+=" operator yet. :) – Graham Oct 27 '17 at 10:52
  • Thank you for reminding me about +=. It has not become habit yet. I know I'm making a lot of silly mistakes and I appreciate your patience. I am aware that because bubble is a variable defined outside of foo that foo does not recognize the variable. I'm thinking in five different directions and mixing everything up. In your example, I've substituted bubble for y in the function call, yes? foo(bubble) is the same as foo(y), and within the function, where y was equal to 50, it is now equal to 100? – Eryn Oct 27 '17 at 11:58
  • @Eryn You'll need to be specific about which version of foo(bubble) you're talking about. Example 1, 2 or 3? y is never equal to 50 though - it starts at 100 in all cases, because that's the value of bubble when you call foo() and pass bubble as the parameter. Whether bubble changes after that will depend on whether you're passing by value (example 1) or by reference (examples 2 and 3). – Graham Oct 30 '17 at 13:27
  • Graham, all of them. Seeing how each one interacted within the function and seeing the return on those functions (like hubble = foo(bubble)) where bubbles only effect (affect?) was that it was reassigned 300 instead of the original 100, but it also affected the value of hubble by assigning the return value of foo(bubble) to hubble (700 because it ended up being y (or bubble) was 100 + 200 and you returned a value of y (bubble) + 400 = 700). I feel like I explained my understanding the long way... – Eryn Oct 30 '17 at 19:02
  • @Eryn Just do it, and see what happens. The best teacher is practical experience! So add cout statements wherever you like, and check what you get at each step. You could even define hubble and bubble as global variables, so that you could print their values from inside foo(). Then swap variables so you do `bubble = foo(hubble);` instead, and see what results you get then. Check whether it's what you expect - and if it isn't, work out where your misunderstanding happened. And once you understand it properly, start your coursework exercise. It should be easy after that. :) – Graham Nov 01 '17 at 11:41
5

Reference variables are a safer alternative to pointers. Usually, when dealing with pointers you don't really care about the pointer (ptr) so much as what it points to (*ptr); and yet, all the time programmers screw up and manipulate ptr instead of *ptr and so on. Consider this code:

void zeroize_by_pointer(int* p)
{
    p = 0; // this compiles, but doesn't do what you want
}

Compare to the reference version,

void zeroize_by_reference(int& p)
{
    p = 0; // works fine
}

There are many other reasons why references are a good idea, but for someone starting out in C++ I'd suggest focusing on this one: it makes it slightly harder to shoot yourself in the foot. Whenever you deal with pointers you're going to be dealing on some level with the machine's memory model, and that's a good thing to avoid when possible.

leftaroundabout
  • 117,950
  • 5
  • 174
  • 319
Rob Hansen
  • 317
  • 1
  • 4
  • Alright, so I feel like I missed a big part of C++, because I don't recall learning ANYTHING about pointers. What I am seeing then is that reference variables do similar things as pointers? I will dig into my book and find more information on pointers because I don't want to get off topic. – Eryn Oct 27 '17 at 07:10
  • 2
    Using references instead of pointers has a much more important point: you can't pass a `null` as a reference (you can, but that's just stupid). This completely eliminates the need for null-checks when you use references. – Clearer Oct 27 '17 at 09:11
  • Dig into your book indeed, or if it hasn't explained references and pointers within the first couple of chapters, then throw it out. – underscore_d Oct 27 '17 at 10:18
  • 1
    @Clearer: ubsan will even detect an attempt to create a "null reference" (I put it in quotes because, as you said, it is not legal to make one). – Arne Vogel Oct 27 '17 at 19:14
4

References were introduced primarily to support operator overloading. Using pointers for "passing via reference" would give you unacceptable syntax according to Bjarne Stroustrup. They also allow aliasing.

In addition, they allow object-oriented programming with a nicer syntax than using pointer explicitly. If you are using classes you must pass references to avoid object slicing.

In summary, you should always prefer using references over bare pointers.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rayniery
  • 1,557
  • 2
  • 12
  • 17
4

There is another, more general advantage of references that pointers do not provide. References by their very nature allow you to express through the function signature that the object referred to must exist at the time the function is called No nulls allowed.

The caller cannot reasonably expect a function that takes a reference to check the validity of that reference..

Pointers, on the other hand, may validly be null. If I write a function that accepts a pointer...

void increment(int* val)
{ 
    (*val)++;
}

...and the caller supplies null, my program is probably going to crash. I can write all the documentation I want stating that the pointer must not be null but the fact is it's pretty easy for someone to pass it in accidentally. So if I want to be safe, I must check for it.

But write this function with a reference and the intent is clear. No nulls allowed.

Joe
  • 5,394
  • 3
  • 23
  • 54
  • Actually not true; consider `function f() {int x=7; return [&](){return x;};}`. – leftaroundabout Oct 27 '17 at 09:05
  • @leftaroundabout He's specifically talking about functions; not lambdas. – Clearer Oct 27 '17 at 09:12
  • 1
    @leftaroundabout Also, it's not relevant, as that's a dangling reference, not a null reference. There is no way to form a null reference except with malformed code. Dangling references just mean the coder didn't think properly, but they're not in the same category of risk. – underscore_d Oct 27 '17 at 10:19
  • @Clearer my point was that references as such don't have any way to guarantee they actually point to a valid object. This is unlike in garbage-collected functional languages or in Rust, where such a guarantee can be given through the extended type/lifetime system. True is, when you call a function with reference arguments with concrete lvalues, then you're sure that within the function body these references are valid. And yes, it's understood that a function with such arguments will work under the assumption that the reference is valid, i.e. “express through the function signature” is right. – leftaroundabout Oct 27 '17 at 11:02
  • 1
    @leftaroundabout You are correct that there is no guarantee. My point was merely that they clarify the intent of the person writing the function, not that they stop you from doing dumb stuff.. :-) – Joe Oct 27 '17 at 16:14
  • @leftaroundabout There's no guarantee that it's a valid reference, but it's at least not null. Just because it doesn't make a stronger guarantee doesn't make it useless to guarantee anything. – leewz Oct 28 '17 at 08:50
  • 1
    @Joe Jim Hyslop and Herb Sutter wrote (what I must call) [C++ fanfiction about null references](http://www.gotw.ca/conv/002.htm). It also mentions that a function must assume the non-null pointers it's given DO lead to valid objects. – leewz Oct 28 '17 at 08:52
  • @leewz I am not one to argue with Herb Sutter. But I was referring to the fact that pointers can be null, not that some non-null pointer might point to something invalid. – Joe Oct 28 '17 at 16:25
  • 1
    @Joe I am not arguing, but giving a potential resource to supplement your answer. My second sentence is about how it suggests that you must sometimes pretend there's a guarantee, making leftaroundabout's point kind of moot, at least for the programmer. – leewz Nov 02 '17 at 20:16
2

There are also different kinds of references. We have lvalue and rvalue references, designated by & and &&, respectively. Generally, a reference tells us something about the lifetime of the object it references, a pointer does not. Compare

void foo(int* i);
void foo(int& i);
void foo(int&& i);

In the first case, i might point to an object we can assign to, but more importantly, it may also be a nullptr or point to one-past-the-end of an array. Thus, dereferencing it may lead to undefined behaviour. Checking for a nullptr is easy enough, the other check is not.

The the second case and third case, i must always reference an valid int we can assign too.

The difference between rvalue and lvalue references is that rvalue/&& references convey the meaning that the referenced value is not needed by anyone else and as such, allows for optimizations. Read up on std::move and move constructors to see what I mean.


To summarize: references tell us something about the object's lifetime. Sure, this could be stated in the documentation, but with pointers, violations of that contract might be hard to catch. References enforce the contract (to a high degree) at compile time and as such provide documentation to the code implicitly. This allows for some quick, uncomplicated optimizations by using e.g. move constructors or perfect forwarding in some cases.

WorldSEnder
  • 4,875
  • 2
  • 28
  • 64
1

You could almost always use reference variables (instead of ever passing by value): for example ...

// this function creates an estimate
// input parameter is the Rooms to be painted
// passed as a const reference because this function doesn't modify the rooms
// return value is the estimated monetary cost
Money createEstimate(const Rooms& rooms)
{
  ...
}

// this function adds paint to the rooms
// input parameter is the Rooms to be painted
// passed as a non-const reference because this function modifies the rooms
void paintRooms(Rooms& rooms)
{
  ...
}

When you pass-by-value instead of pass-by-reference then you implicitly create and pass a copy of the thing ...

// creates and passes a copy of the Rooms to the createEstimate function
Money createEstimate(Rooms rooms)
{
  ...
}

... which (creating a copy) is (often, slightly) slower than passing by reference (furthermore, creating a copy may have side-effects).

As a possible slight performance optimization, and by convention (because people don't care), it's common to pass-by-value instead of pass-be-reference when the type is small and simple (a.k.a. a "primitive" type), for example:

// passes a copy of the x and y values
// returns the sum
int add(int x, int y)
{
  ...
}

... instead of ...

// passes a reference to x and y
// returns the sum
int add(const int& x, const int& y)
{
  ...
}

See also Passing a modifiable parameter to c++ function as well as Why have pointer parameters?

ChrisW
  • 54,973
  • 13
  • 116
  • 224
  • Another case for passing by value is the modern advice to prefer taking parameters by copy and then moving the copy to wherever it needs to be; that avoids having to provide separate overloads for constant and non-constant references. But, like everything else in this thread, that has been discussed to death elsewhere and doesn't need elaborated. – underscore_d Oct 27 '17 at 10:16
  • What's "discussed elsewhere" doesn't necessarily help the OP. – ChrisW Oct 27 '17 at 10:18
  • As you no doubt know (but the OP doesn't), pass-by-value is preferred in principle for encapsulation - preventing code doing funky things with the variables passed to it. Moving to pass-by-reference is an optimisation step you can take when you know enough to know what to avoid, and that's where the const pass-by-reference parameters from your last example come in. As far as a beginner like the OP is concerned, all this is here-be-dragons territory! So he/she shouldn't be concerned with this until *much* later in the course, when he/she has some dragon-avoidance skills. ;) – Graham Oct 27 '17 at 11:04
  • @Graham I wonder though why you wouldn't prefer pass-by-const-reference for "encapsulation". Could preferring pass-by-value be part of the legacy from C, which didn't support references? – ChrisW Oct 27 '17 at 11:07
  • @Graham Are you saying that reference variables secure data better than pass by value against data errors? – Eryn Oct 27 '17 at 12:04
  • @Eryn He was saying that pass-by-value is better than pass-by-reference because it prevents accidental unwanted modification of the original data. – ChrisW Oct 27 '17 at 12:09
  • @ChrisW Alrighty, that is kind of what I was meaning. That is good to know! – Eryn Oct 27 '17 at 12:14
  • @Eryn Whereas it seems to me that you can use pass-by-const-reference instead of pass-by-value, to do that; and I'm wondering why people don't always. – ChrisW Oct 27 '17 at 12:20
  • @ChrisW Which of `Thing` or `Thing const&` to default to is highly context-sensitive and discussed at length on SO and in articles by leading names in the language, as I'm sure you've seen. – underscore_d Oct 27 '17 at 13:01
  • @underscore_d I haven't seen any SO topics or leading-name articles on that topic. Would you like to post any link[s]?. – ChrisW Oct 27 '17 at 15:27
  • @ChrisW At the kind of level we're both working at, you're right - I usually would prefer it in practise, to cut down on stack usage and memory copying. (Or in C, you're talking `const structure_type *const foo` for the same kind of behaviour.) For beginners like Eryn though, if they miss making the reference const (which is a classic mistake) then things can easily go wrong in a hard-to-figure-out way. Until he groks the difference between pass-by-reference and a return statement, he probably should be steered away from further opportunities to shoot himself in the foot. ;) – Graham Oct 30 '17 at 13:37
  • @ChrisW PS. Thanks for clarifying that "unwanted modification" point with Eryn. – Graham Oct 30 '17 at 13:51
  • @Eryn Pass-by-value can be problematic too (e.g. it can cause object slicing as well s object copying), compared to languages like C# or Java which are implicitly pass-by-reference. – ChrisW Oct 30 '17 at 13:58
0

Reference arguments are more used when you pass an object as argument. That way you don't copy the whole variable; usually they come with a const modifier like:

void printDescription(const Person& person) { ... }

That way you don't copy the object.

Sometime the return type is also set as a reference. That way you are returning the same object (and not a copy of it). Have a look at the << operator of ostream. ostream& operator<< (streambuf* sb );.

With variables you can think about the case where you can swap values.

void swap(int & a, int & b) {
    int aux = a;
    int a = b;
    int b = aux;
}

This case in Java, for example, has to be done in a more complex way.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • This is a common example I've been seeing. I don't understand why you would want to switch all of these variables within the function. Is this common within programs, or is it strictly an example of how it works? It appears to me that you have created a list of variables that are all equal, yes? – Eryn Oct 27 '17 at 12:01
  • Some algorithms, like bubble sort, exchange positions of two items on an array. You can do it inside the bubble sort code itself or calling a function which would be cleaner and more modular. When you don't have the reference like in C, you have to create pointers as arguments and use the reference on the call. For example, `scanf("%d", &myInteger);`. In C++ the caller is not responsible for sending the reference, it is the function which specifies it. – Hola Soy Edu Feliz Navidad Oct 27 '17 at 12:09
-4

Reference variables are pointers without a * and practically without pointer arithmetics.

They are not needed from the C++, they are only syntactic sugar around them.

The initial idea of the creators was probably to make C++ code better comprehensible, although they reached its exact opposite.

My opinion is that a C++ program is better if it entirely misses reference variables and it uses only pointers.

Your function in the form

double foo (double studentID* y)
{
  *y = 21654;
  return *y;
}

...would do exactly the same, but it would be actually better comprehensible.

peterh
  • 11,875
  • 18
  • 85
  • 108
  • _"They are not needed"_ OK. Now tell us how you expect operator overloading or generic code to work. Or is that a trick question? Do you think those are unnecessary too? Also, your example is bad, because now the user can pass a null pointer and blow up the program, but references prevent them from doing do and therefore increase safety. – underscore_d Oct 27 '17 at 10:17
  • @underscore_d Operator overloading is imho okay, although the set of the redefinable operators are irrationally limited. Templates in C++ are totally crap, because they can be defined only in the header and they will be compiled always inline. | User passes null pointer accidentally only very rarely and the original example avoids only the first case. – peterh Oct 27 '17 at 10:25
  • 1
    The idea that templates can be defined only in a header is demonstrably false. Also, I think you're overly optimistic about the frequency of occurrence of unwanted null pointers, and besides, I don't think a mechanism for preventing them at compile time can possibly be a bad thing. – underscore_d Oct 27 '17 at 10:27
  • @underscore_d I am sorry to say, but I am sure, also you can see, if something is bad. Yes, C++ is in 90% wonderful, and around 10% of it is bad. I think, also you know this 10%, because somehow you named exactly them. Do you have any idea, why you (and the other, until now 3 downvoters) consider this an insult? I think, it is simply so, we can decide for a task if C++ is the optimal solution or not, that is all. (P.s. I wrote my MSc thesis in C++. I didn't use templates (-> also not STL) and reference variables.) – peterh Oct 27 '17 at 11:00
  • @underscore_d Yes, you can define them also in .cpp files, but so you won't be able to use this code from external libraries :-) I think you are vehemently defending something what I am not attacking. – peterh Oct 27 '17 at 11:04
  • I was one downvoter. I downvoted for saying that C++ should have pointers and no references. IMO there are important differences (explained [here](https://stackoverflow.com/a/3065119/49942) and [here](https://stackoverflow.com/a/1322547/49942)) between pointers and references. – ChrisW Oct 27 '17 at 12:02
  • @ChrisW Reference variables can provide only a weak, compile-time protection from the nullptr deref bugs. My experience is, the overwhelming majority of the nullptr deref bugs is caused by a problem which is inherently impossible to discover in compile time. In exchange, it *seriously* limits the freedom of the programmer, i.e. essentially nothing can be made with it. Although I have also other minority views about the C++ world (for example, I think RAII is a bad idea, instead a parallel, lockfree, mark&sweep GC should have been standardized). – peterh Oct 27 '17 at 14:42
  • @ChrisW Partially on these reasons, I practically never use C++ for productive tasks. In my opinion, the C++ was killed by an incompetent committee. – peterh Oct 27 '17 at 14:45
  • @ChrisW Btw, I am not so hard-lined as [Linus here](http://harmful.cat-v.org/software/c++/linus), and I don't agree fully his view, but I suggest to understand his arguments, too. – peterh Oct 27 '17 at 14:49
  • Yes it's different if you use C (pointers only) or C# (garbage collection). But if you are going to (learn to) use C++ then (IMO) it's better to (know how to) use references idiomatically. – ChrisW Oct 27 '17 at 14:59
  • @ChrisW I know C++ and the reference variables since decades well. If I need to use them, I use them. If I have the choice to avoid them, then I avoid them, because I think they are only a little syntax sugar in exchange of a large feature loss. – peterh Oct 31 '17 at 15:13
  • @underscore_d I am sorry to say, but your statement is false. Templates are compiled always inline in C++ code, it has no acceptable reason, only some decade-old cloudy arguments of some compiler developers that it would be hard to develop. The probable real reason is, that in this sense, the Java way is the correct one, but the C++ committee simply won't admit it by implementing their solution (what would also result that only classes could be templated). – peterh Oct 22 '18 at 17:02
  • @underscore_d (reacting [this](https://stackoverflow.com/questions/46969031/when-is-a-reference-variable-appropriate-and-why-can-you-explain-the-actual-syn/46972508#comment80892823_46972508) ) Nothing avoids the usage of operator overloading with pointers, `*a+=*b`, there `a` and `b` can be pointers to classes without any problem. Of course, you will have these stars what look un-unseful for an unexperienced programmer, however in fact it is *very* useful and needed. Not knowing from something if it is a pointer or not, is a terrible thing in C++. – peterh Oct 22 '18 at 17:05
  • @underscore_d The probable real cause of this problem is that C++ promises to solve the low-level memory-management, bit-manipulating problems automatically with the OOP. The C++ failed to fulfill this promise, and everybody feels it deeply in their soul. C++ is still where it was started: it is a very useful macro language over C. But no one wants to admit it, and this is why my answer got its 4 downs, too. And this is why a "committee" is creating more and more unuseful and meaningless "improvements" to that standard. – peterh Oct 22 '18 at 17:09