Invalid conversion from int** to const int** - c++

I have a class with a 2D array of ints implemented as an int**. I implemented an accessor function to this 2D array as follows, returning a const int** to prevent the user from being able to edit it:
const int** Class::Access() const
{
return pp_array;
}
But I got the compilation error "invalid conversion from int** to const int**". Why is a promotion to const not allowed here? How can I give the user access to the information without editing rights?

Greyson is correct that you'll want to use const int* const*, but didn't explain why your original version failed.
Here is a demonstration of why int** is incompatible with const int**:
const int ci = 0;
const int* pci = &ci;
int* pi;
int** ppi = π
const int** ppci = ppi; // this line is the lynchpin
*ppci = pci;
*pi = 1; // modifies ci!

I was mistaken about the constness of the method being the reason for the error. As Ben points out, the const-ness of the method is irrelavent, since that applies only to the value of the exterior pointer [to pointers to ints], which can be copied to a mutable version trivially.
In order to protect the data (which is your preferred outcome) you should make both the ints and the pointers to ints constant:
int const * const * Class::Access() const
{
return pp_array;
}
Will work.
If you prefer to have the const in front you can also write the declaration like so:
const int * const * Class::Access() const;
but since the second const applies to the pointers, it must be placed to the right (like the const which applies to the method) of the asterisk.

Related

What is the meaning of *&var? [duplicate]

I saw someone using this in one answer:
void methodA(const int*& var);
I couldn't understand what the argument means.
AFAIK:
const int var => const int value which can't be changed
const int* var => pointer to const int, ie *var can't be changed but var can be changed
const int& var => reference to const int, ie value of var can't be changed
What does const int*& var mean? Is const int& *var also possible?
Can you please give some example as well, like what can and can't be done with it?
UPDATE:
I am not sure if I am thinking the right way, but I began to think of a reference as an alias of the variable that was passed as argument, so:
const int * p;
methodA(p) => here we are passing p as const int * but we don't know if this is pass by value or what, until we see the definition of methodA, so if methodA is like this:
methodA(const int * & p2) ==> here p2 is another name to p, ie p and p2 are the same from now on
methodA(const int* p2) ==> here p2 is passed as value, ie p2 is just local to this method
Please correct me if I am thinking the wrong way. If yes, I might need to study some more about this. Can you please point to some nice references?
UPDATE 2:
If some beginner like me wants to know more about this thing, you can use the c++decl / cdecl program from here, which I just discovered to be very useful.
$ c++decl
Type `help' or `?' for help
c++decl> explain const int&* p
declare p as pointer to reference to const int
c++decl> explain const int*& p
declare p as reference to pointer to const int
But, as every one here pointed out, the first example isn't legal in C++.
It is a reference to a pointer to an int that is const.
There is another post somewhat related, actually, here. My answer gives a sorta of general algorithm to figuring these things out.
This: const int& *var has no meaning, because you cannot have a pointer to reference.
If the const's and pointers are getting in the way, remember you can typedef these things:
typedef int* IntPointer;
typedef const IntPointer ConstIntPointer;
void foo(ConstIntPointer&); // pass by reference
void bar(const ConstIntPointer&); // pass by const reference
void baz(ConstIntPointer); // pass by value
Might make it easier to read.
If you need more help on C++, read this. More specifically, references.
References as variables do not take space:
int i; // takes sizeof(int)
int*pi = &i; // takes sizeof(int*)
int& ri = i; // takes no space.
// any operations done to ri
// are simply done to i
References as parameters use pointers to achieve the end effect:
void foo(int& i)
{
i = 12;
}
void foo_transformed(int *i)
{
*i = 12;
}
int main()
{
int i;
foo(i); // same as:
foo_transformed(&i); // to the compiler (only sort of)
}
So it's actually passing the address of i on the stack, so takes sizeof(int*) space on the stack. But don't start thinking about references as pointers. They are not the same.
Some folks find it easier reading this from right to left. So
const int*&
is a reference to a pointer to an integer that is const.
As you know, references cannot be changed, only what they refer to can be changed. So the reference will refer to just one pointer to an integer that is const. Since the pointer is not const - the integer is const - you can change the pointer to point to a different integer.
Compare this to
int* const &
This is a reference to a constant pointer to an integer. Again the reference is immutable, and in this case it is a reference to a constant pointer. What you can change in this case is the integer value since there was no const either side of the int keyword.
Just to add confusion, const int and int const are the same. However int const * and int * const are very different. The first is a pointer to a constant integer, so the pointer is mutable. The second is a constant pointer to an integer, so the integer is mutable.
Hope this helps!
In your example, var is a refernce to a pointer to const char.
Since it's a reference, a change to the parameter inside methodA() will be reflected in the argument that is passed to methodA():
void methodA( const char*& var)
{
static const char newdata[] = {'a', 'b', 'c', '\0'};
printf( "var points to %s\n", var);
var = newdata;
}
int main()
{
const char * p = "123";
printf( "p points to: %s\n", p); // prints "p points to: 123"
methodA( p);
printf( "now p points to: %s\n", p); // prints "now p points to: abc"
}
It is a reference to a const pointer, i.e. a pointer where you cannot modify the data pointed to. As the reference is used as an argument to a method the method is able to modify the pointer to let it point to something else (still something that cannot be modified).
With regards to your update:
so if methodA is like this methodA(const int * & p2) ==> here p2 is another name to p, i.e. p and p2 are same from now on and if methodA(const int* p2) ==> here p2 is passed as value i.e p2 is just local to this method
Yes, you are correct.
Here's another example, a getter that returns the address of a private data item. The item happens to be an int for simplicity. A large array of items would be a more practical case (a zero-copy getter).
#include <iostream>
using namespace std;
class X {
public:
void getter(const int *&data) const
{
data = &val;
}
private:
int val = 5;
};
main()
{
X obj;
const int *data;
obj.getter(data);
cout << data << endl;
cout << *data << endl;
}

C++ read-only array literal

The possibility to create a array literal on read-only memory, exists as the string literal, but doesn't look to extend to other types.
const char* const kChar1{"This is a name"};
const char kChar2[]={"This is a name"};
const int* const kInt1{5,3,2,6,9,0,0,2}; //error
const int kInt2[]{5,3,2,6,9,0,0,2};
I can't create KInt1, like I created kChar1.
How could I create the equivalent?
This is fairly close:
const int kInt2[]{5,3,2,6,9,0,0,2};
const int* const kInt1 = kInt2;
The only real difference is that kInt1 will necessarily point to the same memory as kInt2, but kChar1 does not necessarily point to the same memory as kChar2.
I think this is correct
const int one = 5;
const int two = 10;
const int* const kInt1[] ={&one,&two};

Returning the first pointer of a private array (edit)

I'm trying to learn C++ and OpenGL...
I want to return the first pointer of the array... but maintaing the const correctness...
it happened that:
class Foo{
private:
GLubyte array[64][64][4];
public:
const GLubyte& get_array(){return array;}
}
gives me this compiler error:
:28: error: invalid initialization of reference of type 'const GLubyte&' from expression of type 'GLubyte (*)[64][4]'
can you help me out in understanding how to return the const correctness first pointer?
It has nothing to do with const correctness. If you want the first pointer... well, you need to return a pointer:
const GLubyte* get_array(){return (GLubyte*)array;}
The cast works because arrays are represented continuously in memory.
But i'm pretty sure a better solution to what you're trying to achieve can be devised with std::vector instead of C-style arrays. What exactly are you trying to do?
This has nothing to do with const correctness. You can't return an array of GLubytes as if it was a single GLubyte. You would get the same error message if you removed the const and the & (except that the error message would no longer contain the const and the & either, of course).
Edit in response to your edit: If you want to return a reference to the first element, just return the first element: return array[0][0][0];. If you want to return a pointer to the first element, return the address of the first element (return &array[0][0][0]) and change the return type to GLubyte* instead of GLubyte&.
The type of array is GLubyte * * *, so you cannot convert to a reference, the have to write
GLubyte const & get_array() const { return array[0][0][0]; }
so you get a reference to the first element of array. But if you want the pointer, you have to change your code as follow
GLubyte const * get_array() const { return &(array[0][0][0]); }
If you want something better for your C++ code, you can see also Boost.MultiArray.
If you are after some sort of multi array wrapper then I think this might be close to what you are looking for
class Foo{
private:
std::vector<GLubyte> array;
size_t x_sz, y_sz, z_sz;
public:
Foo(size_t x, size_t y=1, size_t z=1)
: array(x*y*z),
x_sz(x), y_sz(y), z_sz(z)
{}
const GLubyte& element_at(size_t x, size_t y=0, size_t z=0) const
{
return array.at(z*y_sz*x_sz+y*x_sz+x);
}
GLubyte& element_at(size_t x, size_t y=0, size_t z=0)
{
return array.at(z*y_sz*x_sz+y*x_sz+x);
}
GLubyte *data() //returns array
{
return &vector[0];
}
const GLubyte *data() const //returns const array
{
return &vector[0];
}
};

const char* and char const* - are they the same?

From my understanding, const modifiers should be read from right to left. From that, I get that:
const char*
is a pointer whose char elements can't be modified, but the pointer itself can, and
char const*
is a constant pointer to mutable chars.
But I get the following errors for the following code:
const char* x = new char[20];
x = new char[30]; //this works, as expected
x[0] = 'a'; //gives an error as expected
char const* y = new char[20];
y = new char[20]; //this works, although the pointer should be const (right?)
y[0] = 'a'; //this doesn't although I expect it to work
So... which one is it? Is my understanding or my compiler(VS 2005) wrong?
Actually, according to the standard, const modifies the element directly to its left. The use of const at the beginning of a declaration is just a convenient mental shortcut. So the following two statements are equivalent:
char const * pointerToConstantContent1;
const char * pointerToConstantContent2;
In order to ensure the pointer itself is not modified, const should be placed after the asterisk:
char * const constantPointerToMutableContent;
To protect both the pointer and the content to which it points, use two consts.
char const * const constantPointerToConstantContent;
I've personally adopted always putting the const after the portion I intend not to modify such that I maintain consistency even when the pointer is the part I wish to keep constant.
It works because both are same. May be you confused in this,
const char* // both are same
char const*
and
char* const // unmutable pointer to "char"
and
const char* const // unmutable pointer to "const char"
[To remember this, here is a simple rule, '*' affects its whole LHS first]
That is because the rule is:
RULE: const binds left, unless there is nothing on the left, then it binds right :)
so, look at these as:
(const --->> char)*
(char <<--- const)*
both same! oh, and --->> and <<--- are NOT operators, they just show what the const binds to.
(from 2 simple variable initialization question)
A really good rule of thumb regarding const:
Read Declarations Right-to-Left.
(see Vandevoorde/Josutiss "C++ Templates: The Complete Guide")
E.g.:
int const x; // x is a constant int
const int x; // x is an int which is const
// easy. the rule becomes really useful in the following:
int const * const p; // p is const-pointer to const-int
int const &p; // p is a reference to const-int
int * const * p; // p is a pointer to const-pointer to int.
Ever since I follow this rule-of-thumb, I never misinterpreted such declarations again.
(: sisab retcarahc-rep a no ton ,sisab nekot-rep a no tfel-ot-thgir naem I hguohT :tidE
Here is how I always try to interpret:
char *p
|_____ start from the asterisk. The above declaration is read as: "content of `p` is a `char`".
char * const p
|_____ again start from the asterisk. "content of constant (since we have the `const`
modifier in the front) `p` is a `char`".
char const *p
|_____ again start from the asterisk. "content of `p` is a constant `char`".
Hope it helps!
In both of your cases you're pointing to a constant char.
const char * x //(1) a variable pointer to a constant char
char const * x //(2) a variable pointer to a constant char
char * const x //(3) a constant pointer to a variable char
char const * const x //(4) a constant pointer to a constant char
char const * const * x //(5) a variable pointer to a constant pointer to a constant char
char const * const * const x //(6) can you guess this one?
By default, const applies to what is inmediately at is left, but it could apply to what is inmediately at its right if there's nothing preceeding it, as in (1).

non-const pointer argument to a const double pointer parameter

The const modifier in C++ before star means that using this pointer the value pointed at cannot be changed, while the pointer itself can be made to point something else. In the below
void justloadme(const int **ptr)
{
*ptr = new int[5];
}
int main()
{
int *ptr = NULL;
justloadme(&ptr);
}
justloadme function should not be allowed to edit the integer values (if any) pointed by the passed param, while it can edit the int* value (since the const is not after the first star), but still why do I get a compiler error in both GCC and VC++?
GCC: error: invalid conversion from int** to const int**
VC++: error C2664: 'justloadme' : cannot convert parameter 1 from 'int **' to 'const int **'. Conversion loses qualifiers
Why does it say that the conversion loses qualifiers? Isn't it gaining the const qualifier? Moreover, isn't it similar to strlen(const char*) where we pass a non-const char*
As most times, the compiler is right and intuition wrong. The problem is that if that particular assignment was allowed you could break const-correctness in your program:
const int constant = 10;
int *modifier = 0;
const int ** const_breaker = &modifier; // [*] this is equivalent to your code
*const_breaker = & constant; // no problem, const_breaker points to
// pointer to a constant integer, but...
// we are actually doing: modifer = &constant!!!
*modifier = 5; // ouch!! we are modifying a constant!!!
The line marked with [*] is the culprit for that violation, and is disallowed for that particular reason. The language allows adding const to the last level but not the first:
int * const * correct = &modifier; // ok, this does not break correctness of the code