[RESOLVED] read only alias to a pointer
Hi,
I was wondering if there is a way to have a read only alias to a pointer.
let me explain what I am looking for.
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.
Is this possible ?
I tried doing it, but the alias that I thought I created, isn't alias to ptr1 in the first place.
Code:
#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
Re: read only alias to a pointer
Apparently, your code is a bit contradictory. You want ptr2 to be an alias of ptr1. But then you declare ptr2 as follows:
Code:
const int* const & ptr2 = ptr1;
This makes ptr2 a constant pointer to a constant integer. Therefore, ptr2 is not allowed to point to anything else after the initialization with ptr1. So it can't behave like an alias. Got it?
What you really want is that ptr2 is a non-const pointer to an constant integer.
Code:
const int* & ptr2 = ptr1;
However, this won't compile because now you're saying that ptr2 is an alias to ptr1, but ptr2 points to something constant and ptr1 doesn't. So you should declare ptr1 as a pointer to a constant too.
Code:
int* ptr1 = &v1;
//...
const int* & ptr2 = ptr1;
Re: read only alias to a pointer
Thanks ltcmelo, for your reply.
I have given below my views:
Quote:
Originally Posted by
ltcmelo
This makes ptr2 a constant pointer to a constant integer. Therefore, ptr2 is not allowed to point to anything else after the initialization with ptr1. So it can't behave like an alias. Got it?
Lets assume if that statement worked, let me explain what I intended:
If that statement worked, ptr2 would be alias of ptr1.
Yes, ptr2 is not allowed to point to anything else after initialization.
so if ptr1 later points to a variable v2, then ptr2 would also point to the same variable v2.
ptr2 can't modify the variable it points to but ptr1 can.
And why the following statement wouldn't compile was very well explained by Speedo in the thread "const alias to a pointer"
Code:
const int* & ptr2 = ptr1;
The reason why that threw an error is explained below:
For argument sake, lets assume that was permitted by the compiler:
ptr2 would then be alias to ptr1, but ptr2 wouldn't be able to modify the variable it points to.
Lets assume there is a const variable v3.
ptr2 would be able to point to the variable v3, because ptr2 has promised the compiler not to modify that it wouldn't modify anything it points to.
Since ptr2 is an alias of ptr1, now it means that ptr1 is actually pointing to the const v3.
Now since ptr1 is a normal pointer, it is capable of modifying the variable it points to.
So ptr1 would be able to modify the const v3 (leading to undesired or unpredictable results)!!
In order to prevent that, the compiler doesn't allow that.
courtesy : Speedo (thanks to him for that explanation)
Like you pointed out the same example would work fine, if ptr1 was declared as
Code:
const int* ptr1 = &v1
But that isn't what I wanted, bcuz it would mean that ptr1 can't modify v1.
Guess it is still a mystery
Re: read only alias to a pointer
This seems to work as expected when tested on MSVC ( &ptr1 = &ptr2).
On gcc it doesn't seem to work as expected ( &ptr1 != &ptr2 )
seems like a compiler specific issue, I would like to believe MSVC is correct.
Thanks,
Muthu
Re: read only alias to a pointer
Quote:
Originally Posted by Muthuveerappan
This seems to work as expected when tested on MSVC ( &ptr1 = &ptr2).
On gcc it doesn't seem to work as expected ( &ptr1 != &ptr2 )
Please post an updated example that illustrates what you are talking about. You should also state how does it work and how does it not work, respectively.
Re: read only alias to a pointer
Muthuveerappan, I wouldn't put much faith in MSVC being more correct on this point.
I'm puzzled as to why you need this feature, it rarely comes up on discussion, especially with such interest.
Perhaps you could arrange for the effect you're interested in by creating a pair of smart pointer classes. Internally they could operate on non-const references (or even pointers to pointers), but the interface would provide anything you required.
Re: read only alias to a pointer
I hope I have answered the questions, let me know if I am wrong or if I am not clear:
LaserLight,
-------------
I have explained below, what I wanted to achieve.
I suppose it is best to explain with the same example (scroll to top of the page for the code).
(But since you wanted a fresh example, I have pasted one more example below, along with the comments)
Below explanation corresponds to the first example (scroll to top of the page for the code)
Aim - I have a pointer ptr1 that points to v1, I would like to create an alias to ptr1, in such a way that the alias shouldn't be able to modify the variable that ptr1 points.
Suppose, ptr1 is made to point to v2, then ptr2 should also point to v2 and not be able to modify the variable it points to.
This is possible only when ptr2 is an read only alias to ptr1.
Therefore address of ptr1 should be the same as the address of ptr2
In gcc, &ptr1 is different from &ptr2, however in MSVC &ptr1 is the same as &ptr2
Same is evident when you run the above program.
Jvene
--------
The reason I wanted this, was because that it ptr2 would have restricted access, meaning it would only be a read only alias.
Yes, you are correct, the same read only access is achievable by having a pointer to a pointer (implemented in the below example and works ok), but I wanted to achieve this through a read only alias.
I didn't understand what you meant by "creating a pair of smart pointer classes", could you elaborate ?
New Example
-----------------
There is a class called Car, which contains a pointer ptr0.
Aim - A member function should return a read only alias to ptr0.
This is attempted through the function funcReturnConstRef() but on gcc it returns a temporary reference instead.
More comments are available as part of the program:
Code:
/*
There is a class Car, which has a member pointer ptr0.
I would like to return the alias of ptr0, such that the alias can't modify the variable that ptr0 points to.
If the above is acheived, when ptr0 is made to point to a new variable, then the alias would also point to the new variable.
funcReturnConstRef()
--------------------
- This function was built to do the above, but doesn't work on gcc
- In gcc the memory address of ptr0 is different from the reference returned, meaning it is not an alias to ptr0!!
funcReturnPointerToPointer()
----------------------------
- This was implemented as suggested by JVene
- This works ok
*/
#include <iostream>
using std :: cout;
using std :: endl;
class Car
{
public:
Car();
void display() const;
int*& funcReturnRef();
const int* const & funcReturnConstRef(); // Returns the const reference to the pointer
const int* const * funcReturnPointerToPointer(); //Returns a pointer to a pointer (as suggested by JVene)
private:
int* ptr0;
};
int main()
{
system("clear");
Car car1;
car1.display();
int*& ptr1 = car1.funcReturnRef(); //ptr1 would be able to modify the variable it points to
const int* const & ptr2 = car1.funcReturnConstRef(); //ptr2 wouldn't be able to modify the variable it points to
cout << "&ptr1 = " << &ptr1 << "\tptr1 = " << ptr1 << "\t\t*ptr1 = " << *ptr1 << endl;
cout << "&ptr2 = " << &ptr2 << "\tptr2 = " << ptr2 << "\t\t*ptr2 = " << *ptr2 << endl;
//Now if ptr1 is made to point to a different variable, then ptr0 would be pointing to the new variable
//and ideally ptr2 should also point to the new variable but thats not the case in gcc
//gcc
//----
//Throws a warning "returning reference to temporary"
//But the problem here is that address of ptr2 is different from the address of ptr1 (when compile/run in gcc)
const int* const * ptr3 = car1.funcReturnPointerToPointer(); //As suggested by JVene works ok.
cout << "&ptr3 = " << &ptr3 << "\tptr3 = " << ptr3 << "\t\t*ptr3 = " << *ptr3 << endl;
return(0);
}
Car :: Car()
: ptr0(new int)
{
*ptr0 = 10;
}
void Car :: display() const
{
cout << "&ptr0 = " << &ptr0 << "\tptr0 = " << ptr0 << "\t\t*ptr0 = " << *ptr0 << endl;
}
int*& Car :: funcReturnRef()
{
return(ptr0);
}
const int* const & Car :: funcReturnConstRef()
{
return(ptr0);
}
const int* const * Car :: funcReturnPointerToPointer()
{
return(&ptr0);
}
Re: read only alias to a pointer
This is untested pseudo code, and I'm not entirely awake (my second coffee is brewing).
Something like this might work
Code:
template <typename T> class constalias
{
private:
int * p;
public:
constalias( T * & s ) : p( s ) {}
const T * const & operator =( T * s )
{
p = s;
return p;
}
operator const T * const & () { return p; }
};
This isn't complete, but demonstrates the following
Code:
int n = 5;
int * p( &n );
*p = 6; // legal, obviously
constalias<int> a( p ); //creates a read only alias
int d = *a; // works
*a = 7; // compile time error
Obviously you can implement variations to suit your syntax preferences, but the point is you can implement the restrictions you desire through an object representing a "kind of" smart pointer.
Actually, this is a fairly dumb pointer, now that my first sip of the second coffee is waking me up, but I think it brings a new point to the thread.
You might prefer something like
Code:
template <typename T> class constalias
{
private:
int ** p;
public:
constalias( T * & s ) : p( &s ) {}
const T * const & operator =( T *& s )
{
p = &s;
return *p;
}
operator const T * const & () { return *p; }
};
Such that
Code:
int n;
int r;
int * p( &n );
constalias<int> a( p );
n = 5;
r = 10;
*p = 6;
int d = *a;
p = &r;
d = *a;
At which point d is 10.
Re: read only alias to a pointer
Hi JVene,
Thanks for that reply, seems to be something that I never thought of.
could you explain what the following line means:
Code:
operator const T * const & () { return *p; }
1) I mean what is the operator ?
2) what is the return type ?
Re: read only alias to a pointer
Quote:
Originally Posted by Muthuveerappan
1) I mean what is the operator ?
2) what is the return type ?
That is a conversion function that allows one to convert an object of type constalias<T> to a reference to a const pointer to a const T *.
Re: read only alias to a pointer
Thanks laserlight, but I am a little confused and am not sure I fully understand.
I have summed up what I have understood, pls correct me if I am wrong:
I just feel I would understand better, if we can break up the statement.
Let me know if "breaking up into smaller questions" is absurd or incorrect.
Code:
Question Answer
----------- --------------------
1) what is the operator here ? ??
2) return type ? const T * const &
3) how is it invoked (example)? ??
By logging messages I realized that function/operator is not called when the following statement is executed:
Code:
constalias<int> a( p );
It gets called when the following statement is executed (I just added the following statement):
Re: read only alias to a pointer
The operator is called a conversion operator. It's a formal means of providing the compiler with a method to perform an automatic conversion. For example, if I have a string and I want to automatically support the conversion of that to a float, I can provide a conversion operator that returns a float - using something like atof inside the function to perform the conversion.
It is invoked when the compiler is presented with a situation where it would normally issue an error because the conversion isn't possible. Before it does that, however, it searches the object for conversion functions, and if one qualifies it calls the conversion function.
d = *a;
d, being an integer, can't be assigned to a constalias<int>, or as this statement indicates, what's stored at the object - which wouldn't really make much sense because the types aren't compatible. This would result in an error, except...
There is a conversion operator available that returns a const T * const &, where T is an int. In this case, the * in front of the a would make sense, and the compiler calls for the conversion - at which point a now looks like an integer pointer (const though it is), the * in front of that now no longer fires an error.
Similarly:
*a = d;
Would start out performing a similar problem, but here the compiler can't find a solution. First, there's no way a constalias<int> can accept an integer (and we haven't provided any such way). However, the * in front of the a makes even less sense, except for the conversion operator.
The compiler will check for it, but it realizes that even though it might make sense if the conversion were to a plain int *, since the conversion is for a const T * const &, the const will cause the compiler to generate an error - the error should read as though a were an int * to a const int, complaining about the constness of the assignment, not the meaningless notion of a * operator in front of a constalias<int>.
constalias<int> a( p );
In this case, this is simply the construction of a constalias<int>, which accepts an int *&. No conversion is required.
Re: read only alias to a pointer
Hi Muthuveerappan,
It is strange that gcc and MSVC give different results for this!
I think that as an alternative you can use references to serve your purpose :
(note you can modify the object through the non-const reference,
but not through the const reference)
Code:
#include <iostream>
using namespace std;
int main()
{
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& ref1 = v1;
const int & ref2 = ref1;
cout << "ref1 = " << ref1 << endl;
cout << "ref2 = " << ref2 << endl;
cout << "\n\n------------\n\n";
ref1 = v2;
cout << "ref1 = " << ref1 << endl;
cout << "ref2 = " << ref2 << endl;
//ref1 = 42; //*********ALLOWED*************
//ref2 = 44; //*********COMPILER ERROR******
return(0);
}
This works in both environments and yields the same results.
The output in both gcc and MSVC is :
Code:
&v1 = 0012FF60 v1 = 10
&v2 = 0012FF54 v2 = 20
------------
ref1 = 10
ref2 = 10
------------
ref1 = 20
ref2 = 20
Re: read only alias to a pointer
Thanks for the reply Artella, I agree with you that it works for a read only alias to a variable.
We were trying to get a read only alias to a pointer.
Except with the pointer, there is just one more extra step to cover (explained at the beginning of this thread)
"const int * const &" is a solution but it seems to be compiler specific, but there are other ways to accomplish the same, though it might not be as straight forward as "const int * const &":
The following were suggested by JVene
1) pointer to pointer - using a class and a member function to do the same
2) a template class and a more generic and more user friendly implementation of pointer to pointer approach
Re: read only alias to a pointer
Or as another alternative, you could just have a single pointer to a const, and then use const_cast to whenever you want to modify. For example :
Code:
#include <iostream>
using namespace std;
int main(void)
{
int v1 = 10, v2 = 20;
cout << "v1 = " << v1 << endl;
cout << "v2 = " << v2 << endl;
cout << "\n\n------------\n\n";
const int* ptr = &v1;
cout << "*ptr = " << *ptr << endl;
cout << "\n\n------------\n\n";
*const_cast<int *>(ptr) = v2;
//*ptr = v2;//This is NOT ALLOWED
cout << "*ptr = " << *ptr << endl;
return 0;
}
which outputs :
Code:
v1 = 10
v2 = 20
------------
*ptr = 10
------------
*ptr = 20
Re: read only alias to a pointer
Firstly thanks to all of you for coming up with a lot work around methods.
JVene - I am having a look at your implementation, give me some time, I will come back on that, thanks.
Artella, thanks for that idea, it seems like a possibility as well, just feel it is a little risky (I could be completely wrong, correct me if I am wrong)
The idea of casting a "const int*" to a "int *" seems a little risky and wrong to me, again I could be wrong.
The reason I feel that way is because, const int* is not supposed to change the value of the variable it points to. So attempting to do so doesn't seem correct.
I know your original program has managed to do this successfully.
However I feel if you change the variable v1 to a const int variable, it might present a problem
Changes to your program
-------------------------------
I had done some changes to your program to test it further, changes are mentioned below:
1) to include a more detailed cout statement (to include address of variables and pointers)
2) change the declaration of the variable v1 to "const int".
Code:
#include <iostream>
using namespace std;
int main(void)
{
system("clear");
const int v1 = 10;
int v2 = 20;
cout << "&v1 = " << &v1 << "\tv1 = " << v1 << endl;
cout << "&v2 = " << &v2 << "\tv2 = " << v2 << endl;
cout << "\n\n------------\n\n";
const int* ptr = &v1;
cout << "&ptr = " << &ptr << "\tptr = " << ptr << "\t*ptr = " << *ptr << endl;
cout << "\n\n------------\n\n";
*const_cast<int *>(ptr) = v2;
//*ptr = v2;//This is NOT ALLOWED
cout << "&ptr = " << &ptr << "\tptr = " << ptr << "\t*ptr = " << *ptr << endl;
cout << "\n\n------------\n\n";
cout << "&v1 = " << &v1 << "\tv1 = " << v1 << endl;
cout << "&v2 = " << &v2 << "\tv2 = " << v2 << endl;
cout << "\n\n------------\n\n";
return 0;
}
If you see the output of the program, you will realize, finally *ptr shows the value 20, however the value of the value of the constant v1 remains as 10.
And ptr points to v1.
output (removed some blank lines from the output)
Code:
&v1 = 0xbfffd17c v1 = 10
&v2 = 0xbfffd178 v2 = 20
-----------
&ptr = 0xbfffd174 ptr = 0xbfffd17c *ptr = 10
------------
&ptr = 0xbfffd174 ptr = 0xbfffd17c *ptr = 20
------------
&v1 = 0xbfffd17c v1 = 10
&v2 = 0xbfffd178 v2 = 20
------------
Re: read only alias to a pointer
Thanks all for all your valuable inputs, it has helped me understand better.
Thanks JVene, I was able to understand what your program was doing.
It was an interesting idea, and I certainly didn't think from that angle.
In the process I learned the conversion operator, never knew that existed. Thanks.
Just one point, actually with the program (constalias 2nd version), we wouldn't be able to "declare" a read only alias.
We would be stuck at the same point because we were attempting the following :
The conversion operator returns the following type:
const int* const &
This is done is by returning a variable of the type int*
so effectively it is equivalent to:
Code:
int* p1;
const int* const & p2 = p1;
This is exactly where the gcc compiler seems to differ from MSVC.
And therefore the conversion operator actually returns a temporary address and not the way we intended.
Hence we get that warning "warning: returning reference to temporary" while compiling.
The more I look at it the more it seems like a certain compiler bug.
The reason I say that is because, "const int* const &" is meant to be an alias (besides other restrictions it is supposed to impose such as not allowing int* and int** to be modified). But in gcc it simply isn't an alias !
the following would work, till gcc bug is reported and gets fixed:
Code:
#include<iostream>
using namespace std;
int main()
{
system("clear");
int v1 = 10;
int* p1 = &v1;
const int* const * pt = &p1;
const int* const & pa = *pt;
cout << "&v1 = " << &v1 << "\tv1 = " << v1 << endl;
cout << "&p1 = " << &p1 << "\tp1 = " << p1 << "\t*p1 = " << *p1 << endl;
cout << "&pa = " << &pa << "\tpa = " << pa << "\t*pa = " << *pa << endl;
return(0);
}
As you suggested the same could be implemented in the form of a template class to cater to a generic solution.
Thanks again, for all your thoughts, much appreciated !!!
Re: read only alias to a pointer
Well, surprise. MSVC was the better of the two, it seems. There definitely should not be a temporary returned from the conversion function. You've found what should at least be termed an anomaly.
These do exist between compilers, and among versions. It would be very helpful to the community at large if you could say what version of GCC (and which platform might also be helpful, Windows?).
I'm quite confident in template class solutions to these puzzles. The two I listed were terse, suggestive hints that I hoped you'd formalize into a solution you'd prefer, and that expanded into a solution which works around the quirk found in GCC.
Boost has a couple of library components which deal with quirks among compilers, something along the lines of what you've analyzed here. I've not used this one, but (the exact name escapes me) there's a library that deals with initialization. The subject is not related to yours, but apparently:
someobject a = someobect();
Isn't consistent across all compilers, or so the library informs. They have template class solutions to deal with compiler ambiguities so application code can be more portable among them, and more reliable.
So the solution, that of a template class, is in good company.
You've created an interesting thread. It started out seeming an over-focus on a trivial and seldom used idiom (pardon my initial reaction), but it transformed into what amounts to a deeper discussion about how to deal with such issues, and, ultimately, of a the difference we see between compilers when using this language. That's an issue that strikes at all of us.
It's also impressive, now after 17 posts over several days, that you stuck with it until you've reached the beginning of a real resolution. Students, intermediates and visitors should benefit from that example of tenacity.
Re: read only alias to a pointer
The version details are mentioned below:
Compiler - gcc version 4.0.1 (Apple Inc. build 5488)
OS - Mac OS X version 10.5.7
Thanks again to all, for patiently answering the questions, was certainly a big learning for me.
Thanks,
Muthu
Re: read only alias to a pointer
Ouch! I use that compiler :eek:
It occurred to me that you might be able to use a reinterpret_cast in the return from the conversion and assignment operators, unfortunate as that is, but it would be common among compilers if it appeases GCC.