Sign in to follow this  
kelaklub

Ampersand after type

Recommended Posts

I saw this function somewhere and have a question about how it has been declared. Can someone please explain the purpose of having the ampersand (&) after the function return type. I thought it meant the function would return a reference, but this function returns the de-referenced (*this) pointer, which I don't think is a reference.
[SOURCE]
// *************************************************************************
// createVector
// RETURN THE VECTOR BEWEEN TWO POINTS.
// *************************************************************************
template < typename tType >
inline const cl_3dVector < tType > & createVector(const cl_3dPoint < tType > & tail, const cl_3dPoint < tType > & head)
{
    this->x = head.x - tail.x;
    this->y = head.y - tail.y;
    this->z = head.z - tail.z;
    return *this;
}
[/SOURCE]

Share this post


Link to post
Share on other sites
The result of dereferencing a pointer is a reference to the object that the pointer points to. So yes, it's returning a reference to the object.

Share this post


Link to post
Share on other sites
I sorta get it. So if this function's return type was double and it was only returning say the x component of the vector "return (this->x);", then you would not need the ampersand symbol because the function is returning a type double and not an object. Does that sound right?

Share this post


Link to post
Share on other sites
No, it would just be this->x. this->x is already a double &, you can't dereference it any further.

Share this post


Link to post
Share on other sites
Returning direct references to a class' internals is rarely a good idea. Either they should just be public variables, so you don't need to have a function that returns a reference, or they should be insulated behind class functions that can maintain their invariants.

Share this post


Link to post
Share on other sites
I find that it helps to think of references, not as part of a variable's type, but as a calling convention - thus, "return a cl_3dVector< tType > by reference" - and then you indeed return such a thing (*this), and the & just causes it to be returned by reference.

The result of returning it by reference is that the same value is used, rather than a copy. That's not so much an optimization (the compiler is pretty good at removing useless copies) as a useful design trick: references can be used as l-values, so for example you could do createVector(myTail, myHead).doSomething();. It is often the case that member operators will return *this by reference, so that you can "chain" them; this is how things like "cout << foo << bar" work - the result of "cout << foo" is cout, with the printing happening as a side effect, so then "cout << bar" gets evaluated (again printing as a side effect and yielding a reference to cout - but this time there is no more to do, so that reference is just thrown on the floor - note that "cout;" is also a valid C++ statement).

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
references can be used as l-values, so for example you could do createVector(myTail, myHead).doSomething();.

You can do that with an rvalue too.

Share this post


Link to post
Share on other sites
You might want to specify const-reference return value. This will ensure no temporary object will be created for efficiency and also protect your member variable from being undesirably mutated.

[Edit:]
inline const cl_3dVector < tType > & createVector(const cl_3dPoint < tType > & tail, const cl_3dPoint < tType > & head)

Well, :-p you've already did it.

Share this post


Link to post
Share on other sites
Quote:
Original post by kelaklub
Then would you mind explaining where the unhappiness might arise from?


from the constant void in one's life?

Share this post


Link to post
Share on other sites
Quote:
Original post by Skeleton_V@T
You might want to specify const-reference return value. This will ensure no temporary object will be created for efficiency and also protect your member variable from being undesirably mutated.

[Edit:]
inline const cl_3dVector < tType > & createVector(const cl_3dPoint < tType > & tail, const cl_3dPoint < tType > & head)

Well, :-p you've already did it.


Well, that's not quite the whole story...

Share this post


Link to post
Share on other sites
Quote:
Original post by Zahlman
Well, that's not quite the whole story...

Can you explain this a bit further ?
The most relevant question that I've found is
[18.15] Why does the compiler allow me to change an int after I've pointed at it with a const int*?

And he has pointed out one possible situation:

Causing a const int* to point to an int doesn't const-ify the int.
The int can't be changed via the const int*, but if someone else has an int*
(note: no const) that points to ("aliases") the same int, then that int* can be
used to change the int.
For example:


void f(const int* p1, int* p2)
{
int i = *p1; // Get the (original) value of *p1
*p2 = 7; // If p1 == p2, this will also change *p1
int j = *p1; // Get the (possibly new) value of *p1
if (i != j) {
std::cout << "*p1 changed, but it didn't change via pointer p1!\n";
assert(p1 == p2); // This is the only way *p1 could be different
}
}

int main()
{
int x = 5;
f(&x, &x); // This is perfectly legal (and even moral!)
...
}



But in the OP's case, a reference to const value is being returned. Unlike the situation above, I can't have two references - one is const, one isn't - refer to the same thing.

const_cast can't do it.
Reference-to-reference or non-const-pointer-takes-address-of-const-reference doesn't work also.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this