How to obtain pointer to reference member? - c++

Consider this code:
struct AA
{
int& rr;
};
Is there a way to obtain pointer (or maybe reference) to AA::rr in order to obtain this?
AA* aa;
auto mm = &AA::rr; // error: cannot create pointer to reference member ‘AA::rr’
aa ->* mm;
Also in gcc-7.0.1 decltype(AA::mm) is just int&. Is this according to the standard? And does this make sense?
EDIT
Sorry guys, I formulated the question not quite well. No complaints to the fact that references are not objects or that there is no such thing as pointer to a reference. The goal is quite selfish. Given struct AA { int& rr; }; I just want to have a function like this:
template < typename Class, typename Member >
void test(Member Class::*) { }
that when calling test(&AA::rr) I want Class to be AA and Member to be int& or int. So I don't even need the pointer itself but its type that will allow to retrieve the class type and the member type.

How to obtain pointer to reference (member)?
You cannot obtain a pointers to (or references to, or arrays of) references. There is no such type as "pointer to reference" in C++. This is because references are not required to have storage, so there might not even be an address where the reference is stored.
When you apply addressof operator on a reference, what you get is the address of the object that is referred to.

Picture speaks a thousand words
References doesn't really have a container in the memory, they serves more like an alias to the original variable, thus you cannot get pointer to reference because references doesn't have their own memory location.
However, you can get the address of reference, which is the variable it is referencing. In this example, if you cout &rx and &x, they are the same.
So probably you would want to get a pointer to the object it is referencing, rather than pointer to reference

Related

C++ reference to local temporary object

Consider the following template class
template <typename T>
class A {
public:
virtual T const& getContent() = 0;
};
I derive this class using 'int*' as type 'T', as follows
class A1 : public A<int*> {
private:
int a;
public:
int* const& getContent() { return &a; }
};
I got the following warning: 'returning reference to local temporary object'.
Questions:
Does the compiler implicitly instantiate a local temporary object of type 'int * const' from '&a' before returning its reference?
As I do know that A.a really exists, then can I just ignore this warning? Will there be any undesirable side-effects of using this code?
What is the proper way of handling this situation? Do I need to work with the member variable 'int *a' instead. This would be cumbersome.
Yes.
You cannot ignore this warning. A.a exists, but that's not the issue. What you are returning is not a pointer to int, but a reference to a pointer to int, i.e. it is a double indirection. To be specific, a temporary int* was created inside getContent that pointed to A.a. A reference to that temporary was returned, and then the temporary was destroyed. Using the result of getContent will be undefined behavior.
The idiomatic way to handle this situation would typically be to store the member you are passing a const reference to. In other words, have a member int* a, and then simply return a in your function. Returning a const reference is a common way to expose the fully functionality of a data member without allowing the user of the class to mutate it, messing up your class' invariants.
This is incorrect:
T const& getContent() = 0;
You can do:
T const getContent() = 0;
int* const getContent() { return &a; }
First of all...
int* const&
Is the same as...
int *const&
Edit: Originally, I wrongly stated it was equivalent to const int*&. Sorry, that was my fault.
And, references to pointers are more "cumbersome" than pointer themselves (at least IMHO), don't you think so? There's a reason pointers and references shall never be mixed (unless it's a consecuence of template instantiation, of course)...
int const&*
This is impossible, invalid, and last but no least, insane. Although there's no practical way for references to be implemented other than by pointers, they are not objects, in the sense that they (themselves) don't have a sizeof that does not equals that of their referenced type, and the fact that they don't have address at all, at least as far as the Sacred Writings of N4296 are concerned.
But... pointers are objects! The expression &a returns a rvalue (that is basically an object without an address) of type int*. Now, the statement return &a; will take that value and wrap it up in a reference, because...
That's what the function return type expects.
The lifetime of an rvalue of type T can be extended by means of it being holded in a reference of type const T&. However, you can't use this to return references to temporary rvalues.
Now, because all this stuff implies that you're returning a reference to a temporary rvalue in an unallowed way, you where tempted and falled into Undefined Behaviour.
The solution? Simply don't use references to pointers at all in the first place...
int const *getContent() { return a; }
Or, if you prefer it, use references, but not pointers...
int const &getContent() { return *a; }
Now, to the questions!
*Does the compiler implicitly instantiate a local temporary object of type 'int * const' from '&a' before returning its reference?*: Yes and no. It does instantiate such a temporary as explained above (but usually optimized away), but it's type is int*, not int *const, although the latter gets implicitly casted into the former.
As I do know that A.a really exists, then can I just ignore this warning? Will there be any undesirable side-effects of using this code?: That depends on whether you would ignore a divide-by-zero warning.
What is the proper way of handling this situation? Do I need to work with the member variable 'int *a' instead. This would be cumbersome.: You may either use "cumbersome" pointers or "beatiful" references, see above.
I hope this has led some light on you!

Does a pointer to a reference point to the adress of the reference or the value?

Imagine the following scenario:
class ABC
{
public:
int abc;
};
ABC& modifyABC(ABC& foo)
{
foo.abc+=1337;
return foo;
}
void saveABC(ABC& bar, std::vector<ABC*>& list)
{
list.push_back(&modifyABC(bar));
}
int main()
{
ABC foobar;
std::vector<ABC*> ABCList;
saveABC(foobar,ABCList);
return 0;
}
modifyABC() returns a reference to ABC(which is internally some sort of pointer too AFAIK). Does the "adress of" & operator now return a pointer to the adress of the reference or the actually object behind the reference?
modifyABC() returns a reference to ABC (which is internally some sort of pointer too AFAIK)
Not exactly.
Pointers are objects (variables) that require some storage and hold in that storage the address in memory of another object. References are pure aliases, like alternative names. In theory, they do not require any storage at all.
Per Paragraph 8.3.2/4 of the C++11 Standard:
It is unspecified whether or not a reference requires storage (3.7).
So a pointer to a reference is actually a pointer to the referenced object, and any operation done on a reference (apart from the act of binding it to an object upon initialization) is actually done on the object for which the reference is an alias.
I am struggling with the last sentence of your question ("a pointer to the adress of the reference"?)
What can be said is that modifyABC() takes a reference to an ABC, and returns exactly the same reference. No copy of the object is made.
The overall effect of your code is that the address of foobar is appended to ABCList.
Does the "adress of" & operator now return a pointer to the adress of the reference or the actually object behind the reference?
In C++, references, as such, do not have their own addresses. So address of a reference means address of the object the reference is referring to.
X x;
X &r = x; //reference
X *p = &r; //same as &x
Hope that helps.
Anything you do with a reference (including taking its address)
is the equivalent of doing it to the referred to object. In
C++, a reference itself is not an object, does not necessarily
occupy space in memory, and does not have an address.
A reference and a pointer are two different concepts. You may think of a reference as an alias to an existing object. So just like an alias to an alias is again alias of the original, here the return value of modifyABC() is again a reference to the original object. Taking the pointer to a reference always return the address of the object you have a reference of.

"non-const lvalue reference to type cannot bind" error with reference (Type &) but not with pointer (Type *)

I am getting this error "Non-const lvalue to type 'Cell' cannot bind to a temporary of type 'Cell *' with this code :
class RegionHolder
{
public:
RegionHolder(Region& Region1):m_RegionCellNOO(&(Region1.m_NOO))
~RegionHolder();
protected:
Cell & m_RegionCellNOO; // difference is here
};
but not with this one :
class RegionHolder
{
public:
RegionHolder(Region& Region1):m_RegionCellNOO(&(Region1.m_NOO))
~RegionHolder();
protected:
Cell * m_RegionCellNOO; // difference is here
};
I don't understand the problem and would really like to use references and not pointers.
Thanks
You forgot to show us the definition, but presumably Region1.m_NOO is an object of type Cell. Your first example is taking the address of it, and trying to use the resulting pointer to initialise a reference. References aren't initialised from pointers, but from the object itself:
RegionHolder(Region& Region1):m_RegionCellNOO(Region1.m_NOO) {}
// ^ no & ^^ don't forget that
There is one caveat with using references rather than pointers: they are not assignable, and so neither is your class. Often that's not a problem; but if you do need your class to be assignable, then you'll need to use a pointer instead.
The unary & operator gets a pointer to a variable. So, in C++ (as in C) a = &b gets a pointer to b and stores this value in a, so if b is of type int, a needs to be of type int*. Assignment to references, on the other hand, is implicit, so if a is of type int& you simply need to write a=b to make a a reference to b. So in your case, you need to rewrite your constructor as
RegionHolder(Region& Region1):m_RegionCellNOO(Region1.m_NOO) {}
However, I think you're better off using pointers than references here anyway and trying to use C++ without getting comfortable with pointers is a very bad idea. So I suggest you take the time to make yourself comfortable with using pointers instead of trying to avoid them.

Memory allocation for references

Read a lot of differences between pointers & references.
Here is a brief description of what i learned.
1. Memory is allocated when a pointer is defined. A reference however, is a name alias & hence no memory is allocated for it(Is it correct?).
2. Reference is bound to be initialized at the time of definition because, a reference is implemented with a constant pointer & hence cannot be made to point to the other object.
A pointer however, is not necessary to be initialized at the time of definition & hence can also be changed to point to some other object.
3. A reference automatically gets de-referenced. When you write cout << p;
It is automatically de-referenced by the compiler & treated as cout << *p; by the compiler.
Here, p is the reference.
A reference to a reference is not possible.Whenever, you declare a reference to a reference, its actually the reference to the same variable.
e.g.
int i;
int &r1=i;
int &r2=r1; <-------------------2
Compiler interprets the statement 2 as:
int &r2=(*r1)
and (*r1) is nothing but the variable i itself.
A pointer to a pointer is however possible.
5. Array of pointer is possible while array of references is not possible(Why?).
6. Address of pointer is possible. Address of reference is not possible. It gives of the address of the variable.
7. There are situations where you are bound to use references.You cannot use pointers there.
Consider the below example:
A a=b+c;
Where a,b,c are objects of class A.
The operator '+' is overloaded as follows:
const A& operator+(const A& o)
{
return A(i+o.i);
}
See sample code here: http://ideone.com/Q0pE1
Here the reference in the argument list is used to save the memory footprints.
You cannot use pointer in the argument list as you are bound to pass the address of object in the operator function.
A a=&b + &c;
However, if pointer is used in the parameter list, then we will end up adding the addresses rather than object itself.
I want to know that is there any other point that i am missing?
When should one go for pointer & when for reference?
Memory is allocated when a pointer is defined. A reference however, is a name alias & hence no memory is allocated for it
What do you mean by "memory is allocated?" If you mean a heap allocation, as with new or malloc or whatever, no:
int val = 5;
int *pVal = &val; //No dynamic memory allocation.
A pointer has a size, in the same way that int has a size. But that's different from an "allocation".
Reference is bound to be initialized at the time of definition because, a reference is implemented with a constant pointer & hence cannot be made to point to the other object.
No, a reference is bound at initialization time because that's how references work. They are references to objects. The language states that it is impossible for them to not be bound, and it is impossible for their binding to change later. Therefore, it is necessary that references are bound when they are initialized.
How a compiler implements references is entirely irrelevant.
A reference automatically gets de-referenced.
No. There is nothing to de-reference. A reference is merely another name for an already existing object. That's all.
Array of pointer is possible while array of references is not possible(Why?).
Because a reference has to be bound when it is initialized. And it's not possible to give each member of an array a separate object to be bound to. Thus, you would need some step between the creation of the array and the binding of the reference. Which is not allowed.
Address of pointer is possible. Address of reference is not possible. It gives of the address of the variable.
A reference is another name for an already existing object. You can't get the address of a name; you can only get the address of an object.
There are situations where you are bound to use references.
There's nothing stopping you from overloading operator+ for pointers to the types:
A operator+(const A *lhs, const A *rhs) {...}
Of course, this is a non-member function.
Oh, and as a bonus:
const A& operator+(const A& o)
{
return A(i+o.i);
}
This is broken. You're returning a const& to a temporary you create. You should be returning it by value.

Initialising a C++ Reference - why not using the adress-of operator?

Why does the initialisation of C++ references works without the "adress-of" operator (which is &)?
Isn't the assignment of Object with a type A to a reference with a type A& wrong?
Shouldn't the assignment use the "&" operator on the right side?
int var = 2
int& ref = var //why can we assign var of type 'int' to ref of type 'int&'?
int& ref = &var //shouldn't it be like that, so that we will assign the ADRESS to the reference?
EDIT:
To summarize it:
References are alternative names for Objects.
The type of References is created by appending '&' to the type of the referenced object.
References are the same as the references object in every context.
They do not store the memory of the object as pointers do, the presence of the 'adress-of' operator '&' was misleading here.
A reference does not hold the address of the object, as you imply by your comments. That is a pointer. references != pointers.
A reference is an alias to an object which is why that type of assignment works.
int& is a type
&var is an operation to take address.
Same symbol. Totally different menings. Probably designed specifically to keep C++ inaccessible to newcomers.
"I know, that compilers implement referencies as pointers"
No, they don't. This is a common source of confusion. When you do this:
int p;
int *r = &p;
You are creating, say, a 32-bit pointer into memory that you can use to manipulate data.
However, when you do this:
int p;
int& r = p;
You aren't using a pointer to p. There is an object p, that may reside in a register, or the stack or the heap, it's not important. The declaration means that r is also referencing that same object. It is not a pointer to the object: if make a pointer, you're making a new object. You are saying "r points to p." However, using a reference, you are saying "r is p." No new object is created (a pointer). For all intents and purposes, int& r is p, because any use of it references (not points to) p.
Let me put it this way:
It's like saying there's this person, Dave.
He lives at (made up address)
This points to Dave.
And then he has a nickname, OrgnlDave.
OrgnlDave doesn't point to Dave, it is Dave, it is just another way of saying it. There is only one Dave. Saying "hi OrgnlDave" is equal to saying "hi Dave," which is different from sending Dave a letter.
In pseudocode,
person Dave;
address(Dave, made-up-address) pointer;
person& OrgnlDave means Dave; // and we indicate that by using the &
Hi(pointer); // Sends Dave a cordial letter
Hi(Dave); // Says hi to Dave
Hi(OrgnlDave); // Says hi to Dave