Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it impossible to return a reference to a const pointer to const data?

Tags:

c++

I am having some problems trying to return a reference to a const pointer to const data. In the following code, get_pC returns a reference to a const pointer to data:

#include <iostream>
using namespace std;

class C {
public:
    double c;
};

class A {
public:
    C* pC;
    A(const double val):pC(new C){pC->c=val;};
};

class B {
public:
    const A* pA;
    B(const A& a):pA(&a){}; 
    C * const & get_pC() const { return pA->pC; }
};

int main() {
    A a(3.7);
    B b(a);
    C * const & r = b.get_pC();
    r->c=2.2;
    cout<<(long) &b.pA->pC<<endl;
    cout<<(long) &r<<endl;
}

By compiling this code, there is no error shown so it is allowed to modify "c" through "r". That's ok. Moreover, the address of b.pA->pC matches the address of r. That is nice too ^_^

But, when I try to disallow the modification of "c" through "r" is when I experience problems. If I add const to the declaration of "r":

const C * const & r = b.get_pC();

then the compiler complains about the modification of "c". Perfect, that's exactly what I want... right? Unfortunately no, now the addresses of "r" and b.pA->pC are different!!!

Is it impossible to do what I am trying to do? I know that it would be possible to do something "similar" by returning a pointer instead of a reference:

const C * const * get_pC() const { return &pA->pC; }
const C * const * r = b.get_pC();

but it would add one level of indirection and I am curious to know if it is really impossible or there is a way to make it work with references.

like image 625
Jorge Avatar asked Feb 19 '18 19:02

Jorge


People also ask

Can a const function return a reference?

If the thing you are returning by reference is logically part of your this object, independent of whether it is physically embedded within your this object, then a const method needs to return by const reference or by value, but not by non-const reference.

Can I return a const pointer?

The const method prevents you from modifying the members. In case of pointers, this means you can't reassign the pointer.

Is a reference a const pointer?

There are key differences between references and all of the 3 types of const pointers above: Const pointers can be NULL. A reference does not have its own address whereas a pointer does. The address of a reference is the actual object's address.

Can references be const?

The grammar doesn't allow you to declare a “const reference” because a reference is inherently const . Once you bind a reference to refer to an object, you cannot bind it to refer to a different object.


1 Answers

A simpler version of the "problem" would be:

int x;
int *p = &x;

int*       const& r1 = p;
const int* const& r2 = p;

In this case r1 binds directly to p, so &r1 == &p. However, r2 cannot bind directly to p. Instead, the r2 line creates a temporary const int * object and binds r2 to the temporary.

This is always a possibility when using const lvalue references; if the type is not right for direct binding, but an implicit conversion exists, then a temporary may be created.

To avoid the temporary you would need to use a cast:

const int* const & r2 = const_cast<const int* &>(p);

or in your original code:

const C * const & r = const_cast<const C * &>(b.get_pC());

Remark: It's considered poor style to store the address of something that was passed by reference (because the caller does not expect this to happen and the object may end its lifetime). Consider redesigning your code rather than actually using this const_cast solution; e.g. use C * const * get_pC() const { return &pA->pC; } and const C * const * r = b.get_pC();


To summarize the relevant reference binding rule: references only bind directly if the two types are the same, (or a base class reference can bind to derived class), with the left-hand side type possibly having extra top-level qualifiers. See here for more detail, or [dcl.init.ref] section of the Standard.

like image 71
M.M Avatar answered Nov 14 '22 23:11

M.M