Understanding Ampersand (&) in C++

  • C/C++
  • Thread starter guguma
  • Start date
  • Tags
    C++
In summary, references are used when the variable will be changed by the caller, and pointers are used when the variable will not be changed.
  • #1
guguma
51
5
I am totally confused about one peculiar thing in C++.

The "&" as far as I know from C is used to access the address of a variable. When calling a variable by reference, I used to do it with the &'s and *'s (pointers).

I am taking a look at deitels' book on C++, I saw the same pointer structure in C++, it is totally normal but there is also this separate call by reference thing using the & and I do not understand that.

When I do

Code:
int x = 56, &y = x;

This looks to me as I am assigning the value of x to the address of y, where y is an undefined variable?

It is not reasonable. It must be some other thing. Can someone please explain to me how exactly call by reference works in the machine in terms of addresses and values.

And one other thing if & here does not mean "address" but something else, when I am writing a function which takes an address as an argument, how does the compiler differentiate between the two.


Thanks
 
Technology news on Phys.org
  • #2
Using & in the definition of a function in C++ is really just using pointers behind the scenes.
void function(int *a)
{
*a=1;
}

void function(int &a)
{
a =1;
}

Are identical, both change the value of 'a' in the main program - the only reason for the reference form (&) is so you don't forget the '*'

ps. The declaration "int x = 56, &y = x;" is legal but odd, I wouldn't use it - you will confuse other people.
 
  • #3
mgb_phys said:
void function(int &a)
This form is a personal "pet peeve" of mine, and I believe strongly that should NEVER be used. The reason is that some user will eventually call your function and rely on the apparent "copy by value" behavior to assume that x is the same before and after.

//x==y
function(x);
//x!=y ?

IMO, you should always pass by const reference or by pointer (or pass by value for small arguments), never by non-const reference.

void function(const int &a); //looks like pass-by-value to user, and a never modified
void function(int *a); //explicit pass-by-pointer, user knows a may be modified
 
  • #4
mgb_phys said:
Using & in the definition of a function in C++ is really just using pointers behind the scenes.
void function(int *a)
{
*a=1;
}

void function(int &a)
{
a =1;
}

Are identical, both change the value of 'a' in the main program - the only reason for the reference form (&) is so you don't forget the '*'
There are (at least) two other differences between pointers and references. Firstly, you cannot change the value of a reference. To extend mgb_phys' example, suppose the pointer version of the function had received a constant pointer -- void function(int * const a). With this modification, the pointer version of the function is now very close to how references work. That pointers use *a=1 (or a->foo for a class/structure) and references use a=1 (or a.foo) is syntactical sugar.

guguma said:
int x = 56, &y = x;
If you are confused by this, remember this much-quoted patient-doctor conversation.
Patient: "Doctor, it hurts when I do this." Doctor: "Don't do that then!"

To understand how this works, think of it in terms of pointers: int x = 56, *y = &x;

A lot less confusion would result if the author of this statement did what software quality experts almost uniformly recommend, which is to declare each variable in a separate declaration statement. One group I work with has a code quality checker that makes the use of the comma in declaration statements illegal.
 
  • #5
DaleSpam said:
IMO, you should always pass by const reference or by pointer (or pass by value for small arguments), never by non-const reference.

IMHO matter on convention. Like var in Pascal.

procedure foobar(foo : integer;var bar: integer);

void foobar(int foo,int &bar);

But you may be right that sticking to const reference or pointer helps avoid nasty bugs.
 
  • #6
DaleSpam said:
This form is a personal "pet peeve" of mine, and I believe strongly that should NEVER be used. The reason is that some user will eventually call your function and rely on the apparent "copy by value" behavior to assume that x is the same before and after. ... IMO, you should always pass by const reference or by pointer (or pass by value for small arguments), never by non-const reference.

void function(const int &a); //looks like pass-by-value to user, and a never modified
void function(int *a); //explicit pass-by-pointer, user knows a may be modified

Dale, you are, to some extent, porting a C mindset to C++. C++ purists much prefer references over pointers. For example, the C++ FAQ-lite, http://www.parashift.com/c++-faq-lite/references.html#faq-8.6", says
C++ FAQ 8.6 said:
When should I use references, and when should I use pointers?
Use references when you can, and pointers when you have to.

I suspect your main beef isn't so much against the use of references as the fact that call-by-reference and call-by-value are indistinguishable on the calling side. The designers of the language didn't consider (or didn't care) how this lack of distinction would impact the maintenance programmer (or a code reviewer, or ...). The reader of a chunk of code is forced to make a lot of context switches between the code being read and interface specifications (e.g., header files) for the functions used by that code.
 
Last edited by a moderator:
  • #7
D H said:
Dale, you are, to some extent, porting a C mindset to C++. C++ purists much prefer references over pointers. For example, the C++ FAQ-lite, http://www.parashift.com/c++-faq-lite/references.html#faq-8.6", says

I suspect your main beef isn't so much against the use of references as the fact that call-by-reference and call-by-value are indistinguishable on the calling side. The designers of the language didn't consider (or didn't care) how this lack of distinction would impact the maintenance programmer (or a code reviewer, or ...). The reader of a chunk of code is forced to make a lot of context switches between the code being read and interface specifications (e.g., header files) for the functions used by that code.
This is exactly my problem. I have no problem whatsoever with the use of const references as there are good performance benefits, particularly with large objects, and the syntax within the function is more convenient. But anyone writing code that might be reused by someone else needs to consider that many people have that C mindset you referred to. They will expect that something that looks like call-by-value will not touch the variable that was passed as an argument.

There is no good reason to pass by non-constant reference. If you are changing the value of the passed variable, then pass it by pointer. That way everyone knows simply by looking at the code that the value may be changed. If you are not changing the value, then pass it by constant reference so that the compiler can do the checking for you.

If you pass by non-constant reference then you might save yourself a couple of seconds writing the code (relative to pass by pointer) but you will inevitably cost some poor user an hour of debugging before he realizes the problem.
 
Last edited by a moderator:
  • #8
One possible reason to pass-by-reference instead of pointer is that references can't be NULL. For a function that returns a result by modifying one of its arguments, at least, a reference makes much more sense and I can't see how someone would expect that the value of the object wouldn't be changed in that case.

In fact, I'd be surprised if there were many cases at all where someone would be confused by pass-by-reference, especially with code autocomplete
 
  • #9
JaWiB said:
One possible reason to pass-by-reference instead of pointer is that references can't be NULL.
This helps the author of the called function, but not the author of the calling function.
For a function that returns a result by modifying one of its arguments, at least, a reference makes much more sense and I can't see how someone would expect that the value of the object wouldn't be changed in that case.

In fact, I'd be surprised if there were many cases at all where someone would be confused by pass-by-reference, especially with code autocomplete

You are thinking to much like a developer. Think of the maintenance programmer or code reviewer who is looking at a bunch of already-written code and sees the line foo->do_something_with(bar); There is no way to know whether foo's do_something_with method modifies bar just by looking at the code at hand. That argument might be call-by-reference or might be call-by-value; the two are completely indistinguishable. One has to look at the interface definition, and one has to do this repeatedly.

Call-by-value, call-by-reference, and call-by-pointer are conceptually different things. The three calling mechanisms are contextually different on the receiving side: foo(int a), bar(int &a), and baz(int * a). The problem is that call-by-value and call-by-reference are contextually identical on the sending side: foo(a), bar(a). Imagine how much easier the maintenance programmer's job would be if, for example, the C++ authors had usurped the '%' character (or whatever) to mean "take the reference of": foo(a) is call-by-value, bar(%a) is call-by-reference. I agree with Dale that this lack of contextual information is a key weakness of C++ (that and the fact that it is a huge language).

DaleSpam said:
There is no good reason to pass by non-constant reference. If you are changing the value of the passed variable, then pass it by pointer.
You are disagreeing with the C++ purists who see pointers as the root of all evil. I understand your concerns, but you are tilting at windmills here.
 
Last edited:
  • #10
D H said:
This helps the author of the called function, but not the author of the calling function.
Isn't it better to get a compiler error when you call foo(0) than a runtime error? It also makes the function more self-documenting, since you don't have to wade through documentation to find out if null is allowed

You are thinking to much like a developer. Think of the maintenance programmer or code reviewer who is looking at a bunch of already-written code and sees the line foo->do_something_with(bar);
True, I've never been anything but a hobbyist

There is no way to know whether foo's do_something_with method modifies bar just by looking at the code at hand. That argument might be call-by-reference or might be call-by-value; the two are completely indistinguishable. One has to look at the interface definition, and one has to do this repeatedly.
Maybe you're right. I don't have the experience to contradict you, but in some cases at least it's fairly obvious just by the function name/argument list/context that one of the arguments is going to be modified. For example, if you declare a variable and never initialize/assign a value to it, then pass it to a function, you can be sure (I think?) that it's passed by reference.

Imagine how much easier the maintenance programmer's job would be if, for example, the C++ authors had usurped the '%' character (or whatever) to mean "take the reference of": foo(a) is call-by-value, bar(%a) is call-by-reference. I agree with Dale that this lack of contextual information is a key weakness of C++ (that and the fact that it is a huge language).
I can't think of a great argument against this. I don't think it's a major shortcoming of C++, but clearly it is a shortcoming since there's been so much debate and no common consensus (as far as I can tell)

I'm not trying to say that you shouldn't pass by pointer; I'm trying to say I think there are cases where passing by reference makes more sense. If the function is at high-risk for the confusion you've mentioned, then it would probably make sense to use a pointer.
 
  • #11
DaleSpam said:
This form is a personal "pet peeve" of mine, and I believe strongly that should NEVER be used. The reason is that some user will eventually call your function and rely on the apparent "copy by value" behavior to assume that x is the same before and after.
Google agrees with you, passing non-const references to funcs is banned in their coding guidelines. Basically for the reason - it has value semantics but pointer behaviour

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Reference_Arguments [Broken]
 
Last edited by a moderator:
  • #12
The fight going on between pointers and references is pretty pleasing but I still find myself confused. In terms of code reading and contexts I too think that references are a trouble but I still do not understand what goes on on the "heap memory" when we introduce an

int &a;

In pointer an:

int *pointer;

is created in an address and takes the value of the address of a variable like this

pointer = &x;

And then when you send the pointer to a function the function takes an address as an argument and you can directly modify the value stored in that address. (I hope I am right about this)

But what happens when I do

int &a = x;

as far as I assume the same thing. a has the address of x as its value, and when I send a reference to a function, the function takes an address as an argument.

Now if I am right about these, what I understand is that the compiler compiles the references as pointers and understands how to interpret &a, and a, from its declaration.

please give me a feedback on this.
 
  • #13
I tested this small example with Visual C++. Referencing is implemented via pointers. I "cleaned" up and commented the assembly code to make it more readable.

Code:
void tstx(int &x)
{
    x = 456;
}

int main()
{
int  a = 123;
int  b = 789;
int &c = b;
    tstx(a);
    tstx(c);
    return(0);
}

Code:
_x$ = +8                                ;offset to x
_tstx   PROC
        push    ebp
        mov     ebp, esp
        mov     eax, DWORD PTR _x$[ebp] ;eax = x = ptr to int
        mov     DWORD PTR [eax], 456    ;*x  = 456;
        mov     esp, ebp
        pop     ebp
        ret     0
_tstx   ENDP

_c$ = -12                               ;offset to c
_b$ = -8                                ;offset to b
_a$ = -4                                ;offset to a
_main   PROC
        push    ebp
        mov     ebp, esp
        sub     esp, 12                 ;allocate space for locals
        mov     DWORD PTR _a$[ebp], 123 ;a = 123;
        mov     DWORD PTR _b$[ebp], 789 ;b = 789;
        lea     eax, DWORD PTR _b$[ebp] ;c = adr b
        mov     DWORD PTR _c$[ebp], eax
        lea     eax, DWORD PTR _a$[ebp] ;eax = adr a
        push    eax                     ;tstx(adr a)
        call    tstx
        add     esp, 4
        mov     eax, DWORD PTR _c$[ebp] ;eax = adr c
        push    eax                     ;tstx(adr c)
        call    tstx
        add     esp, 4
        xor     eax, eax                ;return(0)
        mov     esp, ebp
        pop     ebp
        ret     0
_main   ENDP
 
Last edited:
  • #14
DaleSpam said:
This form is a personal "pet peeve" of mine, and I believe strongly that should NEVER be used. The reason is that some user will eventually call your function and rely on the apparent "copy by value" behavior to assume that x is the same before and after.

//x==y
function(x);
//x!=y ?

IMO, you should always pass by const reference or by pointer (or pass by value for small arguments), never by non-const reference.

void function(const int &a); //looks like pass-by-value to user, and a never modified
void function(int *a); //explicit pass-by-pointer, user knows a may be modified

The flexibility C/C++ offers you is unmatched (aside from assembly), the language offers you multiple ways to achieve the same things. It all comes down to what you like, and what you are doing. For example:

Code:
int add(int &n1, int &n2)
{
    return n1+n2;
}

In the above example, using references is useless, and the parameters should be passed by value. But one must not forget that references make the syntax much easier when compared to the syntax of pointers. A minor example:
Code:
// parameter passed as pointer
void clearVec(std::vector<void*> * vec)
{
   vec->clear();
}
// parameter passed as reference
void clearVec(std::vector<void*> & vec)
{
    vec.clear();
}

Even in that minuscule example above, it is clear that the syntax of references is easier to understand then that of pointers. When you are working with a fairly large function, it is even more clear.

void function(const int &a); //looks like pass-by-value to user, and a never modified
void function(int *a); //explicit pass-by-pointer, user knows a may be modified

Well reading the documentation for any given API is a must if you want to be proficient at using it. Also, new IDEs now come with all sorts of on the fly documentation for functions/classes/etc, such as IntelliSense for Microsoft Visual Studio. I am curious as to how you think the first function looks like it's taking it's parameter by value. It is clearly looks as if the parameter is passed by reference, that is if the user has managed to read the prototype of the function, and if the user is using an advance IDE.
 
  • #15
computerex said:
Even in that minuscule example above, it is clear that the syntax of references is easier to understand then that of pointers.
How? The two only differ in that one uses vec.clear() while the other uses vec->clear().

Well reading the documentation for any given API is a must if you want to be proficient at using it.
That is fine for a developer. However, in a software development activity of a reasonable size and reasonable life-span, other people will read the code. That call-by-value and call-by-reference are indistinguishable means the reader must constantly switch context between the code at hand and the interface definitions. Look at it this way: Do you think the people at Google would have made a rule against non-const call-by-reference (see post #11) if this was not an issue?
 
  • #16
computerex said:
A minor example:


Code:
// parameter passed as pointer
void clearVec(std::vector<void*> * vec)
{
   vec->clear();
}
// parameter passed as reference
void clearVec(std::vector<void*> & vec)
{
    vec.clear();
}

Even in that minuscule example above, it is clear that the syntax of references is easier to understand then that of pointers.
I disagree 100% here. First, to me the syntax of references and pointers here are just as easy to understand. But that isn't my point, my point is that the syntax is hard to understand on the calling side. You are thinking like a person programming for themselves, not like a developer of code that will be used for someone else. If you are just writing for yourself then by all means, do whatever you like. However, if you are writing for others then you need to consider your customers.

computerex said:
It is clearly looks as if the parameter is passed by reference, that is if the user has managed to read the prototype of the function
And if not? As a developer you cannot guarantee that the user of your code will read all of the documentation or look at the prototype of every function. In fact, even if they do read everything it is highly unlikely that they will remember such small details when they are learning the entirety of a new API. Consider your own use of other people's code. Besides, why should a code reviewer have to refer to a completely different document just to determine something as basic as if a function call is call-by-value or call-by-reference? They should have different syntax on the calling side.

Did you know that, in the medical device industry and other industries, a manufacturer can be held liable for accidents caused by equipment which is functioning correctly but is confusing to use? As a result we have a lot of well-designed easy-to-use medical equipment. As software is increasingly being used in medical devices, do you think that the software industry should be held to a different standard?
 
  • #17
D H has it dead on about the 'next guy' thing. According to Steve McConnell's 'Code Complete' most coding world-wide is maintenance coding - circa 90%+.

Taken (too?) literally this means when you write a new module you can expect it will be changed 9 more times in it's lifetime - and it almost assuredly will not be you.
This is what concepts like Halstead vocabulary and McCabe cyclomatic indexes are all about - how hard is it to change code, and how likely is it that you will actually break it when you do change it?
 
  • #18
Jeff -

I am not too sure about MS things like VC++ as examples of how something is supposed to work.

MS has trouble spelling ANSI and ISO, especially in terms of C and C++. Also most standards are written such that they do not specify how to implement something, just what the parameters of the operation are, how they are specified, and what results are guaranteed to be when specified correctly.
 
  • #19
DaleSpam said:
I disagree 100% here. First, to me the syntax of references and pointers here are just as easy to understand. But that isn't my point, my point is that the syntax is hard to understand on the calling side. You are thinking like a person programming for themselves, not like a developer of code that will be used for someone else. If you are just writing for yourself then by all means, do whatever you like. However, if you are writing for others then you need to consider your customers.

Hard to understand on the calling side? I am not sure I understand you correctly. When passing a parameter by reference, you pass it exactly as if you are passing the parameter by value. That's where this entire dilemma started. Tell me this please. When using a function of a third party API, do you not first look at how it's used? Do you not look at the headers, check the API reference, and google the function to see how it's used before using it? You can't use a function without first looking at it's prototype! How will you know what parameters are passed, and how they are passed, or the purpose of the function?
 
  • #20
Because you have to rely on the function not changing the value, even accidentally, and check if the documentation mentions this - and is the documentation correct!
 
  • #21
mgb_phys said:
Because you have to rely on the function not changing the value, even accidentally, and check if the documentation mentions this - and is the documentation correct!

If the function expects a value by reference, and if the reference is not const, then you have to prepare yourself with the possibility, or probability that the value will in fact change. Both pointers and references have their places, and as I said before, it comes down to the programming style of the programmer or the company. You can't guarantee that everyone follows the standards. :)
 
  • #22
computerex said:
Hard to understand on the calling side? I am not sure I understand you correctly. When passing a parameter by reference, you pass it exactly as if you are passing the parameter by value.
That is exactly the problem, and it is exactly why some (e.g., Google) have banned the use of non-const call-by-reference.

Tell me this please. When using a function of a third party API, do you not first look at how it's used? Do you not look at the headers, check the API reference, and google the function to see how it's used before using it? You can't use a function without first looking at it's prototype! How will you know what parameters are passed, and how they are passed, or the purpose of the function?
Stop thinking like a developer! Imagine yourself as a maintenance programmer instead. You have to read through hundreds, and possibly thousands, of lines of code to identify the cause of some problem.

If you have to constantly switch context between the code at hand and the interface specifications of all of the functions called by that code just to understand the code[/i] you might well not have time to identify the problem, let alone fix it. Suppose the code at hand has the function call foo(bar). How can you tell whether foo is receiving a copy of bar or a reference to bar without looking at the spec for foo? Answer: You can't. With C++, things can be much worse than these simple examples because of polymorphism.
 
  • #23
Stop thinking like a developer!

Primary developers don't always think that way either. People who write code that is hard to maintain in my shop find it hard to keep a job here, too. There must be a message in this... The only exception I personally know of is a PC game development, but then the code is documented to death. And still hard to maintain.
 
  • #24
computerex said:
Tell me this please. When using a function of a third party API, do you not first look at how it's used? Do you not look at the headers, check the API reference, and google the function to see how it's used before using it? You can't use a function without first looking at it's prototype! How will you know what parameters are passed, and how they are passed, or the purpose of the function?

Are you checking all these things EACH time you use the function, or do you rely on memory? In the first case you waste a lot of time, in the second - you are risking nasty bugs. There is no such risk if you don't use reference.

And in the real life if something can get broken, it will.
 
  • #25
Borek said:
Are you checking all these things EACH time you use the function, or do you rely on memory? In the first case you waste a lot of time, in the second - you are risking nasty bugs. There is no such risk if you don't use reference.

And in the real life if something can get broken, it will.

Well no, not each time. But I mean once you use the functions enough time, they are etched into your memory. And as I said before, the new IDEs are designed to make this even easier. In Visual Studio 8, if I type, "CreateProcess(" I see the prototype for the function just above, then I can right click the function and go to it's declaration.
 
  • #26
guguma said:
Now if I am right about these, what I understand is that the compiler compiles the references as pointers and understands how to interpret &a, and a, from its declaration. Please give me a feedback on this.

Jeff Reid said:
I tested this small example with Visual C++. Referencing is implemented via pointers. I "cleaned" up and commented the assembly code to make it more readable. (followed by example .cpp and compiler generated .asm).

jim mcnamara said:
I am not too sure about MS things like VC++ as examples of how something is supposed to work.
Note my post was a direct response to guguma's post, to confirm that a compiler compiles references a pointers as asked. I thought the .asm code make it pretty clear references are implement as pointers with VC++.

Is there a C++ compiler that doesn't implement references as pointers?
 
  • #27
The only difference between a reference and a pointer is the syntax, so from the point of view of the compiler, references are pointers.
 

1. What is an ampersand (&) used for in C++?

The ampersand (&) symbol is used in C++ as the "address-of" operator, which is used to obtain the memory address of a variable. It can also be used in function declarations to indicate a pass-by-reference parameter, allowing the function to directly modify the value of the passed-in variable.

2. How does the ampersand (&) differ from the asterisk (*) in C++?

The ampersand (&) and asterisk (*) symbols have different meanings in C++. While the ampersand is used for obtaining the address of a variable, the asterisk is used for dereferencing a pointer to access the value at the memory address it points to.

3. Can the ampersand (&) be used as an arithmetic operator in C++?

No, the ampersand (&) is not an arithmetic operator in C++. It is only used for its special purposes as the "address-of" operator and in function declarations for pass-by-reference parameters.

4. How can I use the ampersand (&) to create a reference in C++?

To create a reference in C++, the ampersand (&) is used in the declaration of the reference variable, following the type of the variable. For example, "int& refVar = originalVar;" creates a reference to the originalVar variable of type int.

5. Are there any best practices for using ampersand (&) in C++?

One best practice for using the ampersand (&) in C++ is to always use the "address-of" operator when taking the address of a variable, to avoid any confusion with the bitwise AND operator. It is also recommended to use references instead of pointers when possible, as they are generally safer and easier to use.

Similar threads

  • Programming and Computer Science
Replies
17
Views
1K
  • Programming and Computer Science
Replies
12
Views
1K
  • Programming and Computer Science
Replies
8
Views
1K
  • Programming and Computer Science
Replies
19
Views
2K
  • Programming and Computer Science
Replies
3
Views
702
  • Programming and Computer Science
Replies
7
Views
3K
  • Programming and Computer Science
Replies
34
Views
2K
Replies
6
Views
1K
  • Programming and Computer Science
Replies
2
Views
1K
  • Programming and Computer Science
Replies
5
Views
846
Back
Top