views:

503

answers:

7

n00b question. I am a C guy and I'm trying to understand some C++ code. I have the following function declaration:

int foo(const string &myname) {
  cout << "called foo for: " << myname << endl;
  return 0;
}

How does the function signature differ from the equivalent C:

int foo(const char *myname)

Is there a difference between using string *myname vs string &myname? What is the difference between & in C++ and * in C to indicate pointers?

Similarly:

const string &GetMethodName() { ... }

What is the & doing here? Is there some website that explains how & is used differently in C vs C++?

+13  A: 

Here, & is not used as an operator. As part of function or variable declarations, & denotes a reference. The C++ FAQ Lite has a pretty nifty chapter on references.

Victor Nicollet
Okay, hold up: look at this website (http://cpp-tutorial.cpp4u.com/structures_functions.html). Scroll to the bottom and see how it treats the add() function using references. In the body of the function, it uses "*p" whereas in your link, there is no "*". what gives?
rascher
I looked at that link, and using * in that context is a bad idea, or might not even work.
Mongoose
I'm pretty sure that's a typo in that tutorial -- probably started out as `int add(int *p)`.
ZoogieZork
Yes, its relying on non-standard behaviour that might change from compiler version to compiler version.
Georg Fritzsche
+5  A: 

string * and string& differ in a couple of ways. First of all, the pointer points to the address location of the data. The reference points to the data. If you had the following function:

int foo(string *param1);

You would have to check in the function declaration to make sure that param1 pointed to a valid location. Comparatively:

int foo(string &param1);

Here, it is the caller's responsibility to make sure the pointed to data is valid. You can't pass a "NULL" value, for example, int he second function above.

With regards to your second question, about the method return values being a reference, consider the following three functions:

string &foo();
string *foo();
string foo();

In the first case, you would be returning a reference to the data. If your function declaration looked like this:

string &foo()
{
    string localString = "Hello!";
    return localString;
}

You would probably get some compiler errors, since you are returning a reference to a string that was initialized in the stack for that function. On the function return, that data location is no longer valid. Typically, you would want to return a reference to a class member or something like that.

The second function above returns a pointer in actual memory, so it would stay the same. You would have to check for NULL-pointers, though.

Finally, in the third case, the data returned would be copied into the return value for the caller. So if your function was like this:

string foo()
{
    string localString = "Hello!";
    return localString;
}

You'd be okay, since the string "Hello" would be copied into the return value for that function, accessible in the caller's memory space.

sohum
Should also note that the second case requires a heap-allocated string and will run into the same problems as the first case if you simply use the address-of operator on a stack-created variable.
Andrew Coleson
+1  A: 

One way to look at the & (reference) operator in c++ is that is merely a syntactic sugar to a pointer. For example, the following are roughly equivalent:

void foo(int &x)
{
    x = x + 1;
}

void foo(int *x)
{
    *x = *x + 1;
}

The more useful is when you're dealing with a class, so that your methods turn from x->bar() to x.bar().

The reason I said roughly is that using references imposes additional compile-time restrictions on what you can do with the reference, in order to protect you from some of the problems caused when dealing with pointers. For instance, you can't accidentally change the pointer, or use the pointer in any way other than to reference the singular object you've been passed.

FryGuy
+3  A: 

The "&" denotes a reference instead of a pointer to an object (In your case a constant reference).

The advantage of having a function such as

foo(string const& myname)

over

foo(string const* myname)

is that in the former case you are guaranteed that myname is non-null, since C++ does not allow NULL references. Since you are passing by reference, the object is not copied, just like if you were passing a pointer.

Your second example:

const string &GetMethodName() { ... }

Would allow you to return a constant reference to, for example, a member variable. This is useful if you do not wish a copy to be returned, and again be guaranteed that the value returned is non-null. As an example, the following allows you direct, read-only access:

class A
{
  public:
  int bar() const {return someValue;}
  //Big, expensive to copy class
}

class B
{
public:
 A const& getA() { return mA;}
private:
 A mA;
}
void someFunction()
{
 B b = B();
 //Access A, ability to call const functions on A
 //No need to check for null, since reference is guaranteed to be valid.
 int value = b.getA().bar(); 
}

You have to of course be careful to not return invalid references. Compilers will happily compile the following (depending on your warning level and how you treat warnings)

int const& foo() 
{
 int a;

 //This is very bad, returning reference to something on the stack. This will
 //crash at runtime.
 return a; 
}

Basically, it is your responsibility to ensure that whatever you are returning a reference to is actually valid.

czuger
note - the caller of the function foo does not know or have to write anything special. He just goes foo(mystr); notice how different this is from a foo that takes a pointer. In that case the caller must go foo( others argue that it is elegant; either way it is what it is
pm100
A: 

In this context & is causing the function to take stringname by reference. The difference between references and pointers is:

  • When you take a reference to a variable, that reference is the variable you referenced. You don't need to dereference it or anything, working with the reference is sematically equal to working with the referenced variable itself.
  • NULL is not a valid value to a reference and will result in a compiler error. So generally, if you want to use an output parameter (or a pointer/reference in general) in a C++ function, and passing a null value to that parameter should be allowed, then use a pointer (or smart pointer, preferably). If passing a null value makes no sense for that function, use a reference.
  • You cannot 're-seat' a reference. While the value of a pointer can be changed to point at something else, a reference has no similar functionality. Once you take a variable by reference, you are effectively dealing with that variable directly. Just like you can't change the value of a by writing b = 4;. A reference's value is the value of whatever it referenced.
Carson Myers
+1  A: 
#include<iostream>
using namespace std;
int add(int &number);

int main ()
{
            int number;
            int result;
            number=5;
            cout << "The value of the variable number before calling the function : " << number << endl;
            result=add(&number);
            cout << "The value of the variable number after the function is returned : " << number << endl;
            cout << "The value of result : " << result << endl;
            return(0);
}

int add(int &p)
{
            *p=*p+100;
            return(*p);
}

This is invalid code on several counts. Running it through g++ gives:

crap.cpp: In function ‘int main()’:
crap.cpp:11: error: invalid initialization of non-const reference of type ‘int&’ from a temporary of type ‘int*’
crap.cpp:3: error: in passing argument 1 of ‘int add(int&)’
crap.cpp: In function ‘int add(int&)’:
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:19: error: invalid type argument of ‘unary *’
crap.cpp:20: error: invalid type argument of ‘unary *’

A valid version of the code reads:

#include<iostream>
using namespace std;
int add(int &number);

int main ()
{
      int number;
      int result;
      number=5;
      cout << "The value of the variable number before calling the function : " << number << endl;
      result=add(number);
      cout << "The value of the variable number after the function is returned : " << number << endl;
      cout << "The value of result : " << result << endl;
      return(0);
}

int add(int &p)
{
      p=p+100;
      return p;
}

What is happening here is that you are passing a variable "as is" to your function. This is roughly equivalent to:

int add(int *p)
{
      *p=*p+100;
      return *p;
}

However, passing a reference to a function ensures that you cannot do things like pointer arithmetic with the reference. For example:

int add(int &p)
{
      *p=*p+100;
      return p;
}

is invalid.

If you must use a pointer to a reference, that has to be done explicitly:

int add(int &p)
{
                    int* i = &p;
      i=i+100L;
      return *i;
}

Which on a test run gives (as expected) junk output:

The value of the variable number before calling the function : 5
The value of the variable number after the function is returned : 5
The value of result : 1399090792
Chinmay Kanchi
A: 

Your function declares a constant reference to a string:

int foo(const string &myname) {
  cout << "called foo for: " << myname << endl;
  return 0;
}

A reference has some special properties, which make it a safer alternative to pointers in many ways:

  • it can never be NULL
  • it must always be initialised
  • it cannot be changed to refer to a different variable once set
  • it can be used in exactly the same way as the variable to which it refers (which means you do not need to deference it like a pointer)

How does the function signature differ from the equivalent C:

int foo(const char *myname)

There are several differences, since the first refers directly to an object, while const char* must be dereferenced to point to the data.

Is there a difference between using string *myname vs string &myname?

The main difference when dealing with parameters is that you do not need to dereference &myname. A simpler example is:

int add_ptr(int *x, int* y)
{
    return *x + *y;
}
int add_ref(int &x, int &y)
{
    return x + y;
}

which do exactly the same thing. The only difference in this case is that you do not need to dereference x and y as they refer directly to the variables passed in.

const string &GetMethodName() { ... }

What is the & doing here? Is there some website that explains how & is used differently in C vs C++?

This returns a constant reference to a string. So the caller gets to access the returned variable directly, but only in a read-only sense. This is sometimes used to return string data members without allocating extra memory.

There are some subtleties with references - have a look at the C++ FAQ on References for some more details.

gavinb