I have a static array of integers that I never want to change. I have a C-style function that wants to have this array as a void-pointer parameter. I am trying out different combinations of const_cast and reinterpret_cast, but I'm coming to the point where I have no clue of what I'm exactly doing and it keeps giving me errors.
class Foo
{
static constexpr int bar[3] = {1,2,3};
void method()
{
cfunction(reinterpret_cast<void*>(const_cast<int*>(&bar)));
}
};
invalid const_cast from type 'const int ()[3]' to type 'int'
I see that it fails because the types don't match. I also tried const_cast<int[]>(bar), but const_cast wants to have a pointer or reference type.
Where can I read up on this subject? It's hard for me to understand what is going on here.
cfunction((void*)bar);
P.S. I 've seen lots of programmers struggling to use all these casts when, in reality, they only need the simple C cast. If you insist on the C++ cast style, then
cfunction(reinterpret_cast<void*>(const_cast<int*>(bar)));
(Remove the & from bar).
As the compiler says, &bar is a const int (*)[3] - a pointer to an array - and you can't const_cast that to an int*.
You want a pointer to the array's first element, not to the array.
That is,
const_cast<int*>(&bar[0])
or, equivalently,
const_cast<int*>(bar)
Of course, this will only be valid if the C function doesn't ever modify the array.
If there is any risk of that, you should not make it const.
If the C function was promising to not modify the data, then it would be taking a const void*. Since it doesn't, it might modify it. So don't make your array const:
class Foo
{
static int bar[3];
void method()
{
cfunction(bar);
}
};
And define the array in the .cpp file of your class:
int Foo::bar[3] = {1, 2, 3};
Related
I'm trying to understand how "pointer to member" works but not everything is clear for me.
Here is an example class:
class T
{
public:
int a;
int b[10];
void fun(){}
};
The following code ilustrate the problem and contains questions:
void fun(){};
void main()
{
T obj;
int local;
int arr[10];
int arrArr[10][10];
int *p = &local; // "standard" pointer
int T::*p = &T::a; // "pointer to member" + "T::" , that is clear
void (*pF)() = fun; //here also everything is clear
void (T::*pF)() = T::fun;
//or
void (T::*pF)() = &T::fun;
int *pA = arr; // ok
int T::*pA = T::b; // error
int (T::*pA)[10] = T::b; // error
int (T::*pA)[10] = &T::b; //works;
//1. Why "&" is needed for "T::b" ? For "standard" pointer an array name is the representation of the
// address of the first element of the array.
//2. Why "&" is not needed for the pointer to member function ? For "standard" pointer a function name
// is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
// That's rule works there.
//3. Why the above pointer declaration looks like the following pointer declaration ?:
int (*pAA)[10] = arrArr; // Here a pointer is set to the array of arrays not to the array.
system("pause");
}
Why "&" is needed for "T::b" ?
Because the standard requires it. This is to distinguish it from accessing a static class member.
From a standard draft n3337, paragraph 5.3.1/4, emphasis mine:
A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed
in parentheses. [Note: that is, the expression &(qualified-id), where the qualified-id is enclosed in
parentheses, does not form an expression of type “pointer to member.” Neither does qualified-id, because
there is no implicit conversion from a qualified-id for a non-static member function to the type “pointer to
member function” as there is from an lvalue of function type to the type “pointer to function” (4.3). Nor is
&unqualified-id a pointer to member, even within the scope of the unqualified-id’s class. — end note]
For "standard" pointer an array name is the representation of the address of the first element of the array.
Not really. An array automatically converts to a pointer to first element, where required. The name of an array is an array, period.
Why "&" is not needed for the pointer to member function ?
It is needed. If your compiler allows it, it's got a bug. See the standardese above.
For "standard" pointer a function name is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
The same thing aplies here as for arrays. There's an automatic conversion but otherwise a function has got a function type.
Consider:
#include <iostream>
template<typename T, size_t N>
void foo(T (&)[N]) { std::cout << "array\n"; }
template<typename T>
void foo(T*) { std::cout << "pointer\n"; }
int main()
{
int a[5];
foo(a);
}
Output is array.
Likewise for functions pointers:
#include <iostream>
template<typename T>
struct X;
template<typename T, typename U>
struct X<T(U)> {
void foo() { std::cout << "function\n"; }
};
template<typename T, typename U>
struct X<T(*)(U)> {
void foo() { std::cout << "function pointer\n"; }
};
void bar(int) {}
int main()
{
X<decltype(bar)> x;
x.foo();
}
Output is function.
And a clarification about this, because I'm not sure what exactly your comment is meant to say:
int arrArr[10][10];
int (*pAA)[10] = arrArr; // Here a pointer is set to the array of arrays not to the array.
Again, array-to-pointer conversion. Note that the elements of arrArr are int[10]s. pAA points to the first element of arrArr which is an array of 10 ints located at &arrArr[0]. If you increment pAA it'll be equal to &arrArr[1] (so naming it pA would be more appropriate).
If you wanted a pointer to arrArr as a whole, you need to say:
int (*pAA)[10][10] = &arrArr;
Incrementing pAA will now take you just past the end of arrArr, that's 100 ints away.
I think the simplest thing is to forget about the class members for a moment, and recap pointers and decay.
int local;
int array[10];
int *p = &local; // "standard" pointer to int
There is a tendency for people to say that a "decayed pointer" is the same as a pointer to the array. But there is an important difference between arr and &arr. The former does not decay into the latter
int (*p_array_standard)[10] = &arr;
If you do &arr, you get a pointer to an array-of-10-ints. This is different from a pointer to an array-of-9-ints. And it's different from a pointer-to-int. sizeof(*p_array_standard) == 10 * sizeof(int).
If you want a pointer to the first element, i.e. a pointer to an int, with sizeof(*p) == sizeof(int)), then you can do:
int *p_standard = &(arr[0);
Everything so far is based on standard/explicit pointers.
There is a special rule in C which allows you to replace &(arr[0]) with arr. You can initialize an int* with &(arr[0]) or with arr. But if you actually want a pointer-to-array, you must do int (*p_array_standard)[10] = &arr;
I think the decaying could almost be dismissed as a piece of syntactic sugar. The decaying doesn't change the meaning of any existing code. It simply allows code that would otherwise be illegal to become legal.
int *p = arr; // assigning a pointer with an array. Why should that work?
// It works, but only because of a special dispensation.
When an array decays, it decays to a pointer to a single element int [10] -> int*. It does not decay to a pointer to the array, that would be int (*p)[10].
Now, we can look at this line from your question:
int (T::*pA3)[10] = T::b; // error
Again, the class member is not relevant to understanding why this failed. The type on the left is a pointer-to-array-of-ints, not a pointer-to-int. Therefore, as we said earlier, decaying is not relevant and you need & to get the pointer-to-array-of-ints type.
A better question would be to ask why this doesn't work (Update: I see now that you did have this in your question.)
int T::*pA3 = T::b;
The right hand side looks like an array, and the left hand side is a pointer to a single element int *, and therefore you could reasonably ask: Why doesn't decay work here?
To understand why decay is difficult here, let's "undo" the syntactic sugar, and replace T::b with &(T::b[0]).
int T::*pA3 = &(T::b[0]);
I think this is the question that you're interested in. We've removed the decaying in order to focus on the real issue. This line works with non-member objects, why doesn't it work with member objects?
The simple answer is that the standard doesn't require it. Pointer-decay is a piece of syntactic sugar, and they simply didn't specify that it must work in cases like this.
Pointers-to-members are basically a little fussier than other pointers. They must point directly at the 'raw' entity as it appears in the object.
(Sorry, I mean it should refer (indirectly) by encoding the offset between the start of the class and the location of this member. But I'm not very good at explaining this.)
They can't point to sub-objects, such as the first element of the array, or indeed the second element of the array.
Q: Now I have a question of my own. Could pointer decay be extended to work on member arrays like this? I think it makes some sense. I'm not the only one to think of this! See this discussion for more. It's possible, and I guess there's nothing stopping a compiler from implementing it as an extension. Subobjects, including array members, are at a fixed offset from the start of the class, so this is pretty logical.
The first thing to note is that arrays decay into pointers to the first element.
int T::*pA = T::b;
There are two issues here, or maybe one, or more than two... The first is the subexpression T::b. The b member variable is not static, and cannot be accessed with that syntax. For pointer to members you need to always use the address-of operator:
int T::*pa = &T::b; // still wrong
Now the problem is that the right hand side has type int (T::*)[10] that does not match the left hand side, and that will fail to compile. If you fix the type on the left you get:
int (T::*pa)[10] = &T::b;
Which is correct. The confusion might have risen by the fact that arrays tend to decay to the first element, so maybe the issue was with the previous expression: int *p = a; which is transformed by the compiler into the more explicit int *p = &a[0];. Arrays and functions have a tendency to decay, but no other element in the language does. And T::b is not an array.
Edit: I skipped the part about functions...
void (*pF)() = fun; //here also everything is clear
void (T::*pF)() = T::fun;
//or
void (T::*pF)() = &T::fun;
It might not be as clear as it seems. The statement void (T::*pf)() = T::fun; is illegal in C++, the compiler you use is accepting it for no good reason. The correct code is the last one: void (T::*pf)() = &T::fun;.
int (T::*pA)[10] = &T::b; //works;
3.Why the above pointer declaration looks like the following pointer declaration ?
int (*pAA)[10] = arrArr;
To understand this, we needn't confuse ourselves with member arrays, simple arrays are good enough. Say've we two
int a[5];
int a_of_a[10][5];
The first (left-most) dimension of the array decays and we get a pointer to the first element of the array, when we use just the array's name. E.g.
int *pa = a; // first element is an int for "a"
int (*pa_of_a)[5] = a_of_a; // first element is an array of 5 ints for "a_of_a"
So without using & operator on the array, when we assign its name to pointers, or pass it to function as arguments, it decays as explained and gives a pointer to its first element. However, when we use the & operator, the decay doesn't happen since we're asking for the address of the array and not using the array name as-is. Thus the pointer we get would be to the actual type of the array without any decay. E.g.
int (*paa) [5] = &a; // note the '&'
int (*paa_of_a) [10][5] = &a_of_a;
Now in your question the upper declaration is a pointer to an array's address without the decay (one dimension stays one dimension), while the lower declaration is a pointer to an array name with decay (two dimensions become one dimension). Thus both the pointers are to an array of same single dimension and look the same. In our example
int (*pa_of_a)[5]
int (*paa) [5]
notice that the types of these pointers are the same int (*) [5] although the value they point to are of different array's.
Why "&" is needed for "T::b" ?
Because that's how the language is specified. It was decided not to complicate the language with a member-to-pointer conversion just for the sake of saving a single character even though, for historical reasons, we have similar conversions for arrays and functions.
For "standard" pointer an array name is the representation of the address of the first element of the array.
No it isn't; it's convertible to a pointer to its first element due to an arcane conversion rule inherited from C. Unfortunately, that's given rise to a widespread (and wrong) belief that an array is a pointer. This kind of confusion is probably part of the reason for not introducing similar bizarre conversions for member pointers.
Why "&" is not needed for the pointer to member function ?
It is. However, your compiler accepts the incorrect void main(), so it may accept other broken code.
For "standard" pointer a function name is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
Again, the function name isn't a pointer; it's just convertible to one.
Why the above pointer declaration looks like the following pointer declaration ?
One is a pointer to an array, the other is a pointer to a member array. They are quite similar, and so look quite similar, apart from the difference which indicates that one's a member pointer and the other's a normal pointer.
Because T on it's own already has a well defined meaning: the type Class T. So things like T::b are logically used to mean members of Class T. To get the address of these members we need more syntax, namely &T::b. These factors don't come into play with free functions and arrays.
A pointer to a class or struct type points to an object in memory.
A pointer to a member of a class type actually points to an offset from the start of the object.
You can think of these kind of pointers as pointers to blocks of memory. These need an actual address and offset, hence the &.
A pointer to function points to the access point of the function in the assembly code. A member method in general is the same as a function that passes a this pointer as the first argument.
That's in crude nut shell the logic behind needing a & to get the address for members and object address in general.
void (*pF)() = fun; //here also everything is clear
It doesn't work because function fun is undefined
int T::*pA = T::b; // error
What is T::b? T::b is not static member. So you need specific object. Instead write
int *pA = &obj.b[0];
Similarly,
int (T::*pA)[10] = &T::b; //works;
It can be compiled. But it will not work as you expected. Make b static or call obj.b to get access to defined member of defined object. We can easily check this. Create conctructor for your class T
class T
{
public:
T() {
a = 444;
}
int a;
int b[10];
void fun(){}
};
On what value points pA ?
int T::*pA = &T::a;
*pA doesn't not point on variable with value 444, because no object has been created, no constructor has been called.
int foo(const uint8_t array[]) {
int x;
for(i=0;i<5;i++){
x= array[i];
}
return 0;
}
it gives a warning as below,
"parameter array could be declared const" ==> i already have declared the array const, i am programming in C++.
First thing to note is that int foo(const uint8_t array[]) is equivalent to int foo(const uint8_t* array), i.e. the function takes a pointer to a const uint8_t, not an array. The pointer itself it not const, the pointee is. The signature should be:
int foo(const uint8_t* const array)
For the record, I don't find this warning particularly useful. The parameter is taken by value and the caller couldn't care less what the function does with it. Furthermore, top level const qualifiers on parameters are ignored when comparing function signatures, and this can lead to some confusion.
void foo(int) and void foo(const int), for example, are identical signatures.
EDIT:
So, according to your comment, MISRA doesn't know that you can't pass arrays by value and complains that array indexing works differently than pointer arithmetic. Shudder... The problem is that you can't add top level const using the array syntax, which makes fixes to these two warnings mutualy exclusive.
Try tricking it like this, then:
typedef const uint8_t Array[];
int foo(const Array arr);
Remember that, despite the syntax, the function actually takes a pointer, and is equivalent to
int foo(const uint8_t * array)
So array points to an array of constant bytes; but is not itself constant. The warning is pointing out that, since the function doesn't modify the pointer, it could (and, at least according to this rule, should) be constant:
int foo(const uint8_t * const array)
There is another way and it seems to be under the <iterator>
To move your pointer forward 'safely' you simply use std::advance(array, 1) then to access that value you simply dereference (*array), the location, this seems to get rid of the MISRA warning in question.
I'm trying to understand how "pointer to member" works but not everything is clear for me.
Here is an example class:
class T
{
public:
int a;
int b[10];
void fun(){}
};
The following code ilustrate the problem and contains questions:
void fun(){};
void main()
{
T obj;
int local;
int arr[10];
int arrArr[10][10];
int *p = &local; // "standard" pointer
int T::*p = &T::a; // "pointer to member" + "T::" , that is clear
void (*pF)() = fun; //here also everything is clear
void (T::*pF)() = T::fun;
//or
void (T::*pF)() = &T::fun;
int *pA = arr; // ok
int T::*pA = T::b; // error
int (T::*pA)[10] = T::b; // error
int (T::*pA)[10] = &T::b; //works;
//1. Why "&" is needed for "T::b" ? For "standard" pointer an array name is the representation of the
// address of the first element of the array.
//2. Why "&" is not needed for the pointer to member function ? For "standard" pointer a function name
// is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
// That's rule works there.
//3. Why the above pointer declaration looks like the following pointer declaration ?:
int (*pAA)[10] = arrArr; // Here a pointer is set to the array of arrays not to the array.
system("pause");
}
Why "&" is needed for "T::b" ?
Because the standard requires it. This is to distinguish it from accessing a static class member.
From a standard draft n3337, paragraph 5.3.1/4, emphasis mine:
A pointer to member is only formed when an explicit & is used and its operand is a qualified-id not enclosed
in parentheses. [Note: that is, the expression &(qualified-id), where the qualified-id is enclosed in
parentheses, does not form an expression of type “pointer to member.” Neither does qualified-id, because
there is no implicit conversion from a qualified-id for a non-static member function to the type “pointer to
member function” as there is from an lvalue of function type to the type “pointer to function” (4.3). Nor is
&unqualified-id a pointer to member, even within the scope of the unqualified-id’s class. — end note]
For "standard" pointer an array name is the representation of the address of the first element of the array.
Not really. An array automatically converts to a pointer to first element, where required. The name of an array is an array, period.
Why "&" is not needed for the pointer to member function ?
It is needed. If your compiler allows it, it's got a bug. See the standardese above.
For "standard" pointer a function name is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
The same thing aplies here as for arrays. There's an automatic conversion but otherwise a function has got a function type.
Consider:
#include <iostream>
template<typename T, size_t N>
void foo(T (&)[N]) { std::cout << "array\n"; }
template<typename T>
void foo(T*) { std::cout << "pointer\n"; }
int main()
{
int a[5];
foo(a);
}
Output is array.
Likewise for functions pointers:
#include <iostream>
template<typename T>
struct X;
template<typename T, typename U>
struct X<T(U)> {
void foo() { std::cout << "function\n"; }
};
template<typename T, typename U>
struct X<T(*)(U)> {
void foo() { std::cout << "function pointer\n"; }
};
void bar(int) {}
int main()
{
X<decltype(bar)> x;
x.foo();
}
Output is function.
And a clarification about this, because I'm not sure what exactly your comment is meant to say:
int arrArr[10][10];
int (*pAA)[10] = arrArr; // Here a pointer is set to the array of arrays not to the array.
Again, array-to-pointer conversion. Note that the elements of arrArr are int[10]s. pAA points to the first element of arrArr which is an array of 10 ints located at &arrArr[0]. If you increment pAA it'll be equal to &arrArr[1] (so naming it pA would be more appropriate).
If you wanted a pointer to arrArr as a whole, you need to say:
int (*pAA)[10][10] = &arrArr;
Incrementing pAA will now take you just past the end of arrArr, that's 100 ints away.
I think the simplest thing is to forget about the class members for a moment, and recap pointers and decay.
int local;
int array[10];
int *p = &local; // "standard" pointer to int
There is a tendency for people to say that a "decayed pointer" is the same as a pointer to the array. But there is an important difference between arr and &arr. The former does not decay into the latter
int (*p_array_standard)[10] = &arr;
If you do &arr, you get a pointer to an array-of-10-ints. This is different from a pointer to an array-of-9-ints. And it's different from a pointer-to-int. sizeof(*p_array_standard) == 10 * sizeof(int).
If you want a pointer to the first element, i.e. a pointer to an int, with sizeof(*p) == sizeof(int)), then you can do:
int *p_standard = &(arr[0);
Everything so far is based on standard/explicit pointers.
There is a special rule in C which allows you to replace &(arr[0]) with arr. You can initialize an int* with &(arr[0]) or with arr. But if you actually want a pointer-to-array, you must do int (*p_array_standard)[10] = &arr;
I think the decaying could almost be dismissed as a piece of syntactic sugar. The decaying doesn't change the meaning of any existing code. It simply allows code that would otherwise be illegal to become legal.
int *p = arr; // assigning a pointer with an array. Why should that work?
// It works, but only because of a special dispensation.
When an array decays, it decays to a pointer to a single element int [10] -> int*. It does not decay to a pointer to the array, that would be int (*p)[10].
Now, we can look at this line from your question:
int (T::*pA3)[10] = T::b; // error
Again, the class member is not relevant to understanding why this failed. The type on the left is a pointer-to-array-of-ints, not a pointer-to-int. Therefore, as we said earlier, decaying is not relevant and you need & to get the pointer-to-array-of-ints type.
A better question would be to ask why this doesn't work (Update: I see now that you did have this in your question.)
int T::*pA3 = T::b;
The right hand side looks like an array, and the left hand side is a pointer to a single element int *, and therefore you could reasonably ask: Why doesn't decay work here?
To understand why decay is difficult here, let's "undo" the syntactic sugar, and replace T::b with &(T::b[0]).
int T::*pA3 = &(T::b[0]);
I think this is the question that you're interested in. We've removed the decaying in order to focus on the real issue. This line works with non-member objects, why doesn't it work with member objects?
The simple answer is that the standard doesn't require it. Pointer-decay is a piece of syntactic sugar, and they simply didn't specify that it must work in cases like this.
Pointers-to-members are basically a little fussier than other pointers. They must point directly at the 'raw' entity as it appears in the object.
(Sorry, I mean it should refer (indirectly) by encoding the offset between the start of the class and the location of this member. But I'm not very good at explaining this.)
They can't point to sub-objects, such as the first element of the array, or indeed the second element of the array.
Q: Now I have a question of my own. Could pointer decay be extended to work on member arrays like this? I think it makes some sense. I'm not the only one to think of this! See this discussion for more. It's possible, and I guess there's nothing stopping a compiler from implementing it as an extension. Subobjects, including array members, are at a fixed offset from the start of the class, so this is pretty logical.
The first thing to note is that arrays decay into pointers to the first element.
int T::*pA = T::b;
There are two issues here, or maybe one, or more than two... The first is the subexpression T::b. The b member variable is not static, and cannot be accessed with that syntax. For pointer to members you need to always use the address-of operator:
int T::*pa = &T::b; // still wrong
Now the problem is that the right hand side has type int (T::*)[10] that does not match the left hand side, and that will fail to compile. If you fix the type on the left you get:
int (T::*pa)[10] = &T::b;
Which is correct. The confusion might have risen by the fact that arrays tend to decay to the first element, so maybe the issue was with the previous expression: int *p = a; which is transformed by the compiler into the more explicit int *p = &a[0];. Arrays and functions have a tendency to decay, but no other element in the language does. And T::b is not an array.
Edit: I skipped the part about functions...
void (*pF)() = fun; //here also everything is clear
void (T::*pF)() = T::fun;
//or
void (T::*pF)() = &T::fun;
It might not be as clear as it seems. The statement void (T::*pf)() = T::fun; is illegal in C++, the compiler you use is accepting it for no good reason. The correct code is the last one: void (T::*pf)() = &T::fun;.
int (T::*pA)[10] = &T::b; //works;
3.Why the above pointer declaration looks like the following pointer declaration ?
int (*pAA)[10] = arrArr;
To understand this, we needn't confuse ourselves with member arrays, simple arrays are good enough. Say've we two
int a[5];
int a_of_a[10][5];
The first (left-most) dimension of the array decays and we get a pointer to the first element of the array, when we use just the array's name. E.g.
int *pa = a; // first element is an int for "a"
int (*pa_of_a)[5] = a_of_a; // first element is an array of 5 ints for "a_of_a"
So without using & operator on the array, when we assign its name to pointers, or pass it to function as arguments, it decays as explained and gives a pointer to its first element. However, when we use the & operator, the decay doesn't happen since we're asking for the address of the array and not using the array name as-is. Thus the pointer we get would be to the actual type of the array without any decay. E.g.
int (*paa) [5] = &a; // note the '&'
int (*paa_of_a) [10][5] = &a_of_a;
Now in your question the upper declaration is a pointer to an array's address without the decay (one dimension stays one dimension), while the lower declaration is a pointer to an array name with decay (two dimensions become one dimension). Thus both the pointers are to an array of same single dimension and look the same. In our example
int (*pa_of_a)[5]
int (*paa) [5]
notice that the types of these pointers are the same int (*) [5] although the value they point to are of different array's.
Why "&" is needed for "T::b" ?
Because that's how the language is specified. It was decided not to complicate the language with a member-to-pointer conversion just for the sake of saving a single character even though, for historical reasons, we have similar conversions for arrays and functions.
For "standard" pointer an array name is the representation of the address of the first element of the array.
No it isn't; it's convertible to a pointer to its first element due to an arcane conversion rule inherited from C. Unfortunately, that's given rise to a widespread (and wrong) belief that an array is a pointer. This kind of confusion is probably part of the reason for not introducing similar bizarre conversions for member pointers.
Why "&" is not needed for the pointer to member function ?
It is. However, your compiler accepts the incorrect void main(), so it may accept other broken code.
For "standard" pointer a function name is the representation of the function address, so we can write &funName or just funName when assigning to the pointer.
Again, the function name isn't a pointer; it's just convertible to one.
Why the above pointer declaration looks like the following pointer declaration ?
One is a pointer to an array, the other is a pointer to a member array. They are quite similar, and so look quite similar, apart from the difference which indicates that one's a member pointer and the other's a normal pointer.
Because T on it's own already has a well defined meaning: the type Class T. So things like T::b are logically used to mean members of Class T. To get the address of these members we need more syntax, namely &T::b. These factors don't come into play with free functions and arrays.
A pointer to a class or struct type points to an object in memory.
A pointer to a member of a class type actually points to an offset from the start of the object.
You can think of these kind of pointers as pointers to blocks of memory. These need an actual address and offset, hence the &.
A pointer to function points to the access point of the function in the assembly code. A member method in general is the same as a function that passes a this pointer as the first argument.
That's in crude nut shell the logic behind needing a & to get the address for members and object address in general.
void (*pF)() = fun; //here also everything is clear
It doesn't work because function fun is undefined
int T::*pA = T::b; // error
What is T::b? T::b is not static member. So you need specific object. Instead write
int *pA = &obj.b[0];
Similarly,
int (T::*pA)[10] = &T::b; //works;
It can be compiled. But it will not work as you expected. Make b static or call obj.b to get access to defined member of defined object. We can easily check this. Create conctructor for your class T
class T
{
public:
T() {
a = 444;
}
int a;
int b[10];
void fun(){}
};
On what value points pA ?
int T::*pA = &T::a;
*pA doesn't not point on variable with value 444, because no object has been created, no constructor has been called.
I have written following 3 functions in C++. Kindly explain me how all return types are different? And how the return values will be stored in Memory? I know const keyword applies to whatever is on immediate left but i need more explanation.
const int* sample1();
int* const sample2();
int const* sample3();
const int* sample1();
int const* sample3();
These functions are identical. They return pointer to constant memory (this memory cannot be changed via this pointer). But we can change pointer itself. Increment it for example.
int* const sample2();
This function returns constant pointer to non-constant memory. We cannot change pointer itself, but we can change the memory it is point.
const does not have to apply to whatever is on immediate right. For example
class Foo
{
void Bar() const;
int var;
}
This will will ban the function Bar in Foo to alter any member variables in the object.
Besides this us2012's comment sums it all up.
I might be totally of but this seems like a school assignment or something?
Here's a code snippet that hopefully conveys what I'm trying to do:
void updatePointer(const int*& i)
{
i++;
}
int main() {
int array[5];
int* arrayPtr = array;
updatePointer(arrayPtr );
return 0;
}
This gives compiler error:
prog.cpp: In function ‘int main()’:
prog.cpp:16: error: invalid initialization of reference of type ‘const int*&’ from
expression of type ‘int*’
prog.cpp:5: error: in passing argument 1 of ‘void updatePointer(const int*&)’
Supposing that you could do it, you could write the following:
const int c = 0;
void updatePointer(const int* &i) {
i = &c;
}
int main() {
int *ptr;
updatePointer(ptr);
*ptr = 1; // attempt to modify the const object c, undefined behavior
}
The purpose of const is to ensure that user code cannot attempt to modify a const object unless it contains a const-cast (or equivalent). So the compiler has to refuse this code. Forbidding a const int*& from binding to an int* is the only place in the code above that's reasonable for the compiler to refuse: every other line is fine.
It's the same reason you can't implicitly convert int** to const int **.
Aside from the motivation in terms of const-safety, you can think if it in terms of int* being a different type from const int*, that just so happens to be convertible to it. Likewise, you can convert int to double, but a double& can't bind to an int lvalue. That's not the full reason, because actually int* and const int* have the same size and representation, whereas int and double don't. So there could be a special-case to allow it if not for the fact that it would break the const system.
The reason that C++ has both const and non-const overloads for strchr is related to this issue: your function updatePointer modifies its input rather than returning the updated value, but the principle is similar. The C-style single strchr allows you to "launder" a pointer-to-const into a pointer-to-non-const without a cast, and it's a hole in the const system. C++ (a) has overloading and (b) has a stricter type system than C, so it closes that hole.
If you want your real function updatePointer to work like strchr -- examine the data pointed to and compute a new value for the pointer, then you're in the same situation that strchr is. That's regardless of what it does with the new value (return it in the case of strchr, write it back in the case of updatePointer), because the issue is that you want the new pointer to have the same const-qualification as the input. You need to provide either const- and non-const overloads or a function template.
If you only need your real function updatePointer to move a pointer by a certain distance, regardless of the data pointed to, you could use std::advance instead.
What you wrote is a function taking a reference to a pointer to a const int. What you're asking for would be
updatePointer(int* const & i);
However this doesn't make much sense. Passing a reference to a pointer seems to imply that you intend to modify the pointer, but you cannot do it because it is declared const. As it is you'd obtain the same effect by just passing your pointer as in
updatePointer(int* i);
Found this
Copied here in case the link breaks in future:
The reasoning is a little awkward to comes to grips with. The main question is:
Since a "const int&" can be bound to an "int", why can't a "const int*&" be bound to a "int*"?
Basically, once you add a level of indirection (a pointer) then the rules change. With just a single level of indirection (as in a single *), the rule can be stated as:
A reference to a pointer to a cv-qualified type can be bound to anything of that same type whose cv-qualifications are less than or equal to that of the pointer (which is a reference).
(Read that a few times.)
So the reason a "const int*&" can't be bound to a "int*" is because "const int*" and "int*" are two different types (underlined part of the rule is broken).