to reference or not to reference in function return type

I have the following class:

1
2
3
4
5
6
7
8
9
10
11
class Person {
public:
    Person(const string & name, int age): name{name}, age{age} {};
    
    const string & getName() const {return this->name;}
    int getAge() const {return this->age;}

private:
    string name;
    int age;
};


and I'm struggling to understand this part:
 
    const string & getName() const {return this->name;}


1- I would assume that I need to reference the return value "&(this-name)" to make it compatible with "string &", but then I get a "string<char>& to string<char>*" error. Aren't reference types basically immutable pointers that dereference automatically by assignment?

2- To add insult to injury :), the compiler let's me happily change the code to:
 
    const string getName() const {return this->name;}

and works just fine. Isn't there a difference between "string &" and "string"?

Follow up:
Considering that string provides move semantics (I don't know much about it, just that the compiler recognizes rvalues and moves their resources instead of copying), is there much difference between the following two lines? If so, what are they?

 
    const string & getName() const {return this->name;}


 
    const string getName() const {return this->name;}


I may be a little bit overwhelmed, right now. So, apologies for the confusion :-)
Thank you!
Last edited on
general rule of thumb: reference anything bigger than an integer. strings, vectors, classes, etc all should be passed around by reference. This just saves a lot of time spent copying data, its a performance hit to copy when you do not need to. If you do not want to change it, put const on it. If you do want to change it, document it as a side effect.

this is useful if you have the same thing twice or confusion. avoid unnecessary thising.
foo::func(string sigh)
this->sigh = sigh; // you need to qualify this->sigh because the parameter has same name as the class variable.
foo::func(string sigh_in)
sigh = sigh_in; //no need for a this, it can tell which is which.
and finally in the second example I could still say this->sigh but it is just visual clutter best avoided. That is, just say: return name;

that said..
1) references are not true pointers. the compiler may directly use the same token for the reference and the real item without a third party pointer in the middle, and it WILL do this where it can. There are some places where it may have to use a pointer, but I do not know compiler and code generation well enough to say when anymore. That is if you have ref that is referring to x, and x is at address 1234, the compiler may generate assembly using address 1234 for both x and ref without an extra layer of access via a true pointer.

string & and string are different.
but they are used the same way:
s = func(); //works whether func returns reference or copy. it matters under the hood, but both will work.

its that under the hood that is getting you.

Maybe this will clear up some of the mystery:
const string & getName() const {return this->name;} //returns a reference to the actual value. you could say this... const string &ref = object.getname(); and then, if you did object.setname(), ref HAS ALSO CHANGED. you are not doing this, you are copying whats in the ref to a target.

const string getName() const {return this->name;} //this is just going to copy the data.

in action:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class foo
{  
  public:
  int x;
  const int &getx() {return x;}
};

int main()
{
foo f;
f.x = 1234;
const int &xref = f.getx();
cout << xref << endl;
f.x = 777;
cout << xref << endl;
return 0;
}


C:\c>a
1234
777
Last edited on
Hi jonnin and thank you for your reply,

Sorry, I'm late, I needed some time to digest some of the material.

Here's what I got:
1- Generally, reference instead of copying everything bigger than an int
2- The overused thising is because I'm overwhelmed and try to be explicit as much as possible to decrease the pressure on my brain for now :)
3- There was this property of references that I completely forgot: References take automatically the address of the variable that is assigned to them. So, I can't write string & s = &myPrevString because it is already done by the compiler. So, string & s = myPrevString implicitly takes the address of the myPrevString.
Correct me if I'm wrong, if I wanted to use an actual pointer it would be like this string * s = &myPrevString, because the pointer doesn't implicitly take the address but the address needs to be assigned to it explicitly.

Not properly understanding this property, I think, was something that confused me between a function's return type, the value that it actually returns, and the type of the variable that takes that value.

I mark this as solved, but please don't hesitate to remind me if there is something I've missed.

Thanks again.
: References take automatically the address of the variable that is assigned to them.


This implies that they're some kind of pointer. They're not.
This also implies that a reference-to-an-object has some kind of separate existence to the object, and that it has to have an address "assigned". It doesn't.

A reference is another name for the exact same object at the exact same place in memory. It's an alias. Another name for the exact same object.

When the time comes to actually implement references in a real implementation of C++, then maybe, in SOME cases, under the hood, the compiler will use pointers to create the effect needed, but that's up to the compiler. STOP thinking that references are pointers. It's causing you problems.

So, string & s = myPrevString implicitly takes the address of the myPrevString.

No, it does not. s does not "take the address" of anything. s is another name for the string myPrevString.
Last edited on
LOL, thank you.

I already read somewhere that they are aliases but trying to "understand" the behind the scenes made me think of them as special pointers, which caused all of these problems in the first place. And until right now, I never understood the value of thinking of them as aliases.

I feel enlightened, hahah!

Thanks!

so do you understand my post now? and the code snip? And what happens if you take the & off xref variable?
Yes, sure!
Your explanation and the code snippet helped me think about references and how they work in the first place.

Although, you explicitly mentioned that "references are not true pointers", I still kept this notion in my head, not understanding the value of this statement while trying to "understand" how it works behind the scenes.

I think I've the hang of it now, until next time when I come back totally confused :-)

Thanks!
Topic archived. No new replies allowed.