Dismiss Notice
Join Physics Forums Today!
The friendliest, high quality science and math community on the planet! Everyone who loves science is here!

Ampersand in C++

  1. Jul 23, 2008 #1
    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 seperate call by reference thing using the & and I do not understand that.

    When I do

    Code (Text):
    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
     
  2. jcsd
  3. Jul 23, 2008 #2

    mgb_phys

    User Avatar
    Science Advisor
    Homework Helper

    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.
     
  4. Jul 23, 2008 #3

    Dale

    Staff: Mentor

    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
     
  5. Jul 23, 2008 #4

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    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.

    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.
     
  6. Jul 24, 2008 #5

    Borek

    User Avatar

    Staff: Mentor

    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.
     
  7. Jul 24, 2008 #6

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    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.
     
  8. Jul 24, 2008 #7

    Dale

    Staff: Mentor

    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 refered 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.
     
  9. Jul 24, 2008 #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
     
  10. Jul 24, 2008 #9

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    This helps the author of the called function, but not the author of the calling function.
    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).

    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: Jul 24, 2008
  11. Jul 25, 2008 #10
    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

    True, I've never been anything but a hobbyist

    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.

    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.
     
  12. Jul 25, 2008 #11

    mgb_phys

    User Avatar
    Science Advisor
    Homework Helper

    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
     
  13. Jul 25, 2008 #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.
     
  14. Jul 26, 2008 #13

    rcgldr

    User Avatar
    Homework Helper

    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 (Text):

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

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

    _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: Jul 26, 2008
  15. Jul 28, 2008 #14
    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 (Text):

    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 (Text):

    // 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.

    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.
     
  16. Jul 28, 2008 #15

    D H

    User Avatar
    Staff Emeritus
    Science Advisor

    How? The two only differ in that one uses vec.clear() while the other uses vec->clear().

    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?
     
  17. Jul 28, 2008 #16

    Dale

    Staff: Mentor

    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.

    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?
     
  18. Jul 28, 2008 #17

    jim mcnamara

    User Avatar
    Science Advisor
    Gold Member

    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?
     
  19. Jul 28, 2008 #18

    jim mcnamara

    User Avatar
    Science Advisor
    Gold Member

    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.
     
  20. Jul 28, 2008 #19
    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?
     
  21. Jul 28, 2008 #20

    mgb_phys

    User Avatar
    Science Advisor
    Homework Helper

    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!
     
Know someone interested in this topic? Share this thread via Reddit, Google+, Twitter, or Facebook

Have something to add?



Similar Discussions: Ampersand in C++
  1. To C or not to C (Replies: 31)

  2. C or C++? (Replies: 8)

  3. Java or C/C ++ (Replies: 5)

Loading...