alias to a pointer such that it the alias is read only

Hi,

I am a new user. I was wondering if there is a way to have a alias to a pointer such that the alias is read only (I mean not the the variable it points to is not modifiable)

I have explained with an example (code is given below for reference)

suppose v1 is an int variable, and ptr1 is a pointer to v1.

suppose the alias to ptr1 is ptr2.

I want an alias to ptr1, in such a way that the alias doesn't modify the variable v1.

When ptr1 points to v2, the alias also must point to v2, but should not be able to modify v2.

I tried doing it, but the alias that I thought I created, isn't alias to ptr1 in the first place.

Question
---------
a) Is this possible, if so how is it achievable ?
b) In my example, why is ptr2 having a different address from that of ptr1, am I missing something ?

Let me know if you need more information.

Thanks,
Muthu
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
using namespace std;


int main()
{
    system("clear");

    int v1 = 10, v2 = 20; 


    cout << "&v1   = " << &v1 << "\t\tv1   = " << v1 << endl; 
    cout << "&v2   = " << &v2 << "\t\tv2   = " << v2 << endl; 

    cout << "\n\n------------\n\n";

    int* ptr1 = &v1;
        
    const int* const & ptr2 = ptr1;
        
    cout << "&ptr1 = " << &ptr1 << "\t\tptr1 = " << ptr1 << "\t*ptr1 = " << *ptr1 << endl;
    cout << "&ptr2 = " << &ptr2 << "\t\tptr2 = " << ptr2 << "\t*ptr2 = " << *ptr2 << endl;


    cout << "\n\n------------\n\n";
        
    ptr1 = &v2;

    cout << "&ptr1 = " << &ptr1 << "\t\tptr1 = " << ptr1 << "\t*ptr1 = " << *ptr1 << endl;
    cout << "&ptr2 = " << &ptr2 << "\t\tptr2 = " << ptr2 << "\t*ptr2 = " << *ptr2 << endl;

    return(0);
}


Thanks,
Muthu
Very strange! I would have thought for sure that this would work -- but I can't seem to get it to work right either.

Sorry I don't have an answer for you, I just had to respond because this was so bizarre. Great question. I'd like to know the answer too.
There's one too many const on line 19: int * const & ptr2 = ptr1;
I'm trying to figure out what the other const does.

EDIT: It would seem the first const in 'const int * const &' makes the reference point to the int, not the int *, and when you do &ptr2, you're actually taking the address of the reference, not the thing the reference points to.
Last edited on
const int* const & ptr2 = ptr1;
ptr2 is reference to a constant pointer to constant int
Last edited on
int * const & ptr2 = ptr1; This solution doesn't make the pointer point to a const int, though. IE: *ptr2 = 0; would not generate a compiler error -- which is the desired result here.

To my knowledge, const int* const makes a const pointer to a const int. The OP's desired goal is to have a reference to such a pointer -- so that the pointer nor the value it points to can be modified via the reference.

1
2
3
4
5
    const int a = 0;
    const int* const b = &a;
    const int* const &c = b;

    assert(&c == &b);


I tried this code and it works. However, the OP is trying to have 'c' point to const int while 'b' points to const. I wouldn't think this wouldn't be a problem, but as soon as you remove the first const, it's separating things into separate variables (the reference is no longer a real reference!)

1
2
3
4
          int* const b = &a;
    const int* const &c = b;

    assert(&c == &b);  // fails 


I wonder if this is a compiler bug.
This seems to be working fine, for me:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
#include <iostream>

int main(){
	int v1[]={10,20,30,40};
	std::cout
		<<"v1 = "<<v1<<'\t'
		<<"*v1 = "<<*v1<<'\t'
		<<std::endl; 
	const int *ptr1=v1;	
	//constant reference to pointer to constant int
	//const int * const &ptr2=ptr1;
	//reference to pointer to constant int
	const int * /*const */&ptr2=ptr1;
	std::cout
		<<"&ptr1 = "<<&ptr1<<'\t'
		<<"ptr1 = "<<ptr1<<'\t'
		<<"*ptr1 = "<<*ptr1<<'\t'
		<<std::endl;
	std::cout
		<<"&ptr2 = "<<&ptr2<<'\t'
		<<"ptr2 = "<<ptr2<<'\t'
		<<"*ptr2 = "<<*ptr2<<'\t'
		<<std::endl;
	ptr2++;		// increment of read-only reference (if const int * const &ptr2)
	//(*ptr2)++;	// increment of read-only location
	std::cout
		<<"&ptr1 = "<<&ptr1<<'\t'
		<<"ptr1 = "<<ptr1<<'\t'
		<<"*ptr1 = "<<*ptr1<<'\t'
		<<std::endl;
	std::cout
		<<"&ptr2 = "<<&ptr2<<'\t'
		<<"ptr2 = "<<ptr2<<'\t'
		<<"*ptr2 = "<<*ptr2<<'\t'
		<<std::endl;
	return 0;
}
Nope, it is just a bit of C++ parsing trouble. You'll need a typedef to stand-in for your pointer type:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
using namespace std;

typedef const int* cintptr;

int main()
  {
  int value1 = 42;
  int value2 = -7;

  int* ncp = &value1;

  const cintptr& cpr = ncp;

  cout << "value1 is " << *cpr << endl;

#if 0
  // prove that the addressed item is not modifiable
  *cpr = 12;

  cout << "value1 is now " << *cpr << endl;
#endif

#if 0
  // prove that the referenced pointer itself is not modifiable
  cpr = &value2;

  cout << "value2 is " << *cpr << endl;
#endif

  return 0;
  }

Compile this as-is and it will work fine.

Change line 17 to #if 1 and it will complain something like
a.cpp:19: error: assignment of read-only location '*(const int*)cpr'

Change line 24 to #if 1 and it will complain something like
a.cpp:17: error: assignment of read-only reference 'cpr'

Hope this helps.

[edit] Sorry helios ... I was responding to Disch.
Last edited on
Thanks for your replies, I have given below my views:

Disch:
-------
You are rite, it works when the original pointer (in your case, pointer b) is a constant pointer (meaning it can't modify the variable it points to), but doesn't work when the original pointer is not a constant pointer (meaning, when the pointer can modify the variable it points to).

I am stuck with same problem.

helios:
-------
Array is not best suited to test this example, as v1 is not modifiable anyway.

Lest Assume v1 is not an array, lets assume v1 to be a normal pointer,
then the following statement, would only initialize the ptr1 with the value of v1:

 
const int *ptr1=v1;


changing the value of v1 (I mean, if you make v1 point to another variable x), then ptr1 would still contain the old value of v1
so this doesn't work

Duos:
--------
the memory address of ncp is different from that cpr (see cout statements below):
1
2
    cout << "&ncp = " << &ncp << "\tncp = " << ncp << "\t*ncp = " << *ncp << endl;
    cout << "&cpr = " << &cpr << "\tcpr = " << cpr << "\t*cpr = " << *cpr << endl;


Therefore making ncp point to a new variable will not make cpr point to the new variable
so this doesn't work

Disch:
-------
You are rite, it works when the original pointer (in your case, pointer b) is a constant pointer (meaning it can't modify the variable it points to), but doesn't work when the original pointer is not a constant pointer (meaning, when the pointer can modify the variable it points to).

I am stuck with same problem.


I tried Disch experiment with both MSVC and Mingw. The problem he mentions occurs
in Mingw but not in MSVC.
So it is either a (Mingw/gcc) compiler bug as he suggests or it's one of those 'compiler specific'
things.
Perhaps I have misunderstood your problem, but I thought you asked for a reference to an int pointer...

Sorry I misunderstood. Remember, a reference is different than a pointer in some subtle ways, particularly when you start playing with address-of operators.

What you are asking for is a pointer to a pointer variable, then to perform indirection through that value. That is

+-------+ +------+
| alias |-->| ptr1 |-->something
+-------+ +------+
const mutable

That is: 'alias' cannot be modified or used to modify anything, whereas 'ptr1' can be modified however you like.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <iostream>
using namespace std;

int main()
  {
  int  v1 = 42;
  int  v2 = -7;
  int* ptr1;

  typedef const int* cintptr;

  const cintptr* const alias = &ptr1;

  ptr1 = &v1;

  cout << "value = " << **alias << endl;

  ptr1 = &v2;

  cout << "value = " << **alias << endl;

#if 0
  // prove that **alias cannot be modified
  **alias = 12;
  cout << "value = " << **alias << endl;
#endif

#if 0
  // prove that *alias cannot be modified
  int v3 = 123;
  *alias = &v3;
  cout << "value = " << **alias << endl;
#endif

#if 0
  // prove that alias cannot be modified
  int v4 = 234;
  int* ptr2 = &v4;
  alias = &ptr2;
  cout << "value = " << **alias << endl;
#endif

  return 0;
  }

Notice that you now have to remember to doubly-indirect 'alias' to get to the value. Your code can directly modify 'ptr1' however it likes, and the user's code cannot modify anything... it must still access stuff through 'alias'.

Keep in mind that C and C++ were not designed to provide purely const objects -- you can always cast away the constness and modify things. The only way to get around this is to use the processor's memory management directly to catch attempts toward illegal accesses and modify the attempt yourself. There are some libraries (designed for debugging out-of-bounds array accesses and the like) that do this kind of thing, but the overhead probably isn't worth it.


The only obvious answer to get around it would be to write a class to stand-in for 'alias', much like the STL iterators. I'll come back with an example a little later.

Hope this helps.
Thanks guestgulkan and Disch, I was testing this only on g++ (gcc).

guestgulkan:
----------------
I don't have MSVC, if its not a lot of trouble can u compile and run my first program (at the top of the page) in MSVC.
and can you check if &ptr1 and &ptr2 is the same (from the cout statements).

It could be a compiler bug as you'll suggested.

Thanks all for your valuable inputs.
Hi Duoas,

I wasn't referring to a pointer to a pointer, I was referring to a reference to a pointer.

Lets assume there is a pointer ptr1, pointing to variable v1

Now I would like to create an read only alias to ptr1, lets name the alias ptr2.

ptr1 and ptr2 should have the same memory address.

ptr1 should be able to modify v1, while ptr2 shouldn't be able to modify v1.

----------------
I don't have MSVC, if its not a lot of trouble can u compile and run my first program (at the top of the page) in MSVC.
and can you check if &ptr1 and &ptr2 is the same (from the cout statements).


here is the original code;

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include <iostream>
using namespace std;


int main()
{
    system("clear");

    int v1 = 10, v2 = 20; 


    cout << "&v1   = " << &v1 << "\t\tv1   = " << v1 << endl; 
    cout << "&v2   = " << &v2 << "\t\tv2   = " << v2 << endl; 

    cout << "\n\n------------\n\n";

    int* ptr1 = &v1;
        
    const int* const & ptr2 = ptr1;
        
    cout << "&ptr1 = " << &ptr1 << "\t\tptr1 = " << ptr1 << "\t*ptr1 = " << *ptr1 << endl;
    cout << "&ptr2 = " << &ptr2 << "\t\tptr2 = " << ptr2 << "\t*ptr2 = " << *ptr2 << endl;


    cout << "\n\n------------\n\n";
        
    ptr1 = &v2;

    cout << "&ptr1 = " << &ptr1 << "\t\tptr1 = " << ptr1 << "\t*ptr1 = " << *ptr1 << endl;
    cout << "&ptr2 = " << &ptr2 << "\t\tptr2 = " << ptr2 << "\t*ptr2 = " << *ptr2 << endl;

    return(0);
}



here is the output from MSVC:
&v1 = 0012FF60 v1 = 10
&v2 = 0012FF54 v2 = 20
------------
&ptr1 = 0012FF48 ptr1 = 0012FF60 *ptr1 = 10
&ptr2 = 0012FF48 ptr2 = 0012FF60 *ptr2 = 10
------------
&ptr1 = 0012FF48 ptr1 = 0012FF54 *ptr1 = 20
&ptr2 = 0012FF48 ptr2 = 0012FF54 *ptr2 = 20


Here is the output from Mingw
&v1 = 0x22ff50 v1 = 10
&v2 = 0x22ff4c v2 = 20
------------
&ptr1 = 0x22ff48 ptr1 = 0x22ff50 *ptr1 = 10
&ptr2 = 0x22ff54 ptr2 = 0x22ff50 *ptr2 = 10
------------
&ptr1 = 0x22ff48 ptr1 = 0x22ff4c *ptr1 = 20
&ptr2 = 0x22ff54 ptr2 = 0x22ff50 *ptr2 = 10



The more I look at it, the more I believe that Mingw compiler is the correct one.
Hi guestgulkan,

Thank you so much for testing it on both the compilers and pasting the results.

I would like to believe MSVC is correct because &ptr1 = &ptr2 (meaning ptr2 is an alias to ptr1) but I am not 100% sure that MSVC is correct. If MSVC is correct then we were able to achieve what we wanted.

History of the problem on gcc
------------------------------------
When I first tried this in a program, I had a class which had a member variable of the type int*.

In the member function of that class, I was trying to return the member variable (which was of the type int*). The return type of the function was const int* const &.

The compiler threw a warning that I was attempting to return a temporary address, where as I was actually returning the member variable which was of the type int*. Thats how I knew the program was behaving differently from what I expected it to do.

But one thing is clear, this seems to be compiler specific as Disch had predicted

Thanks once again guestgulkan and Disch
Last edited on
Topic archived. No new replies allowed.