In the code below I am casting pointer type to reference pointer type in order to change the pointer to point somewhere else:
inline void SWAP_POINTERS(void*& p1,void*& p2)
{
void* temp = p1;
p1 = p2;
p2 = temp;
}
When I call the function I ge the following error:
note: candidate function not viable: no known conversion from 'int32_t *' (aka 'int *') to 'void *&' for 1st argument
Do I need to cast?
Why do I need to cast since it is void*?
Limitation: no templates.
calling the code like this:
unsigned int* a;
double* b;
SWAP_POINTERS(a,b);
1. You're probably breaking strict aliasing once you dereference one of the pointers after swapping.
unsigned int* a;
double* b;
SWAP_POINTERS(a,b);
Don't swap pointers which do not point to the same type however. (Note that char aliases other types but that is an exception.)
2. You cannot convert int* to void*& implicitly.
int* is implicitly convertible to void* but the conversion creates an rvalue which cannot be bound to an lvalue reference.
In order to use SWAP_POINTERS with the signature shown in the question, one would have to create lvalues of type void* first and pass those to SWAP_POINTERS.
Example:
int a{0}, b{1};
int * pa = &a;
void * vpa = pa;
int * pb = &b;
void * vpb = pb;
SWAP_POINTERS(vpa, vpb); // swaps vpa and vpb - OF COURSE :)
Please note that this doesn't solve the (probably inteded) swapping of (unrelated) pointers with minimal code. Its just an explanation of why the original code with void*& in place did not work when passing int* and how a call to the original function would have to look in order to be able to operate (on its function arguments...).
3. Swap pointers via std::swap
int a{0}, b{1};
int * pa = &a;
int * pb = &b;
std::swap(pa, pb);
This will do what you think you want, but it's totally NOT recommended. Templates (or std::swap) really are the right answer here.
First, define an inline function to take void **
inline void SWAP_POINTERS2(void** p1,void** p2)
{
void* temp = *p1;
*p1 = *p2;
*p2 = temp;
}
Then, define a macro to perform unpleasant casts.
#define SWAP_POINTERS(a,b) SWAP_POINTERS2((void **) &a, (void **) &b)
Or, if you prefer using static_cast:
#define SWAP_POINTERS(a,b) SWAP_POINTERS2(static_cast<void**>(static_cast<void *> (&a)), static_cast<void**>(static_cast<void *>(&b)))
Now this "works" to the extent that it compiles and does what you want. I have no idea how you'd then use the swapped pointers, of course...
unsigned int* a;
double* b;
SWAP_POINTERS(a,b);
Related
I was writing a C++ function that takes int** as input and the function itself does not modify the data (i.e. matrix elements). So I decided to make the argument a const int** type (Is that an acceptable practice?). A sample code is like this:
void func1(const int* k) {
std::cout << *k << '\n';
}
void func2(const int** k) {
std::cout << **k << '\n';
}
int main() {
int m = 0;
int* p1 = &m;
func1(p1);
int** p2 = &p1;
func2((const int**)p2); // compilation error unless explicit type conversion
// func2(p2); /* [*] compilation error */
(**p2) += 1;
func1(p1);
func2((const int**)p2);
return 0;
}
My question is, when calling func2, I have to explicitly convert the double-pointer p2 to const int**, otherwise it gives the following error:
error: invalid conversion from ‘int**’ to ‘const int**’ [-fpermissive]
Whereas func1 has no such issue. I tested this with both g++ (10.2.0) on Cygwin and Intel's icpc. Could someone explain why the compiler behaves this way and what is a good practice in this situation?
In a sense, having a const int ** is saying "this pointer points to a pointer to an integer that won't be modified". The problem with implicitly casting an int ** to const int ** is that that promise is easy to mistakenly not keep. For example:
const int c = 1;
int *p1;
const int **p2 = &p1; /* implicit cast from int** to const int** */
*p2 = &c; /* change what the pointed-to pointer points to */
*p1 = 2; /* change a value pointed to by a const int** */
So the requirement for an explicit cast is to make you think about this, I guess.
Example adapted from here.
With multiple levels of pointers, a type is only more const-qualified if every level of pointer from the right has const added. This is for const-correctness reasons so that when you assign to the pointer, you can't accidentally assign a more const-qualified pointer at the "lower" levels of pointers when you have multiple pointers.
For example:
int *** * * * i;
int ***const*const*const* j = i;
// ^ All levels after this have to be const-qualified
This includes the left-most type, const int. So, if your data is not modified, you should have int const* const* k.
This is the case in C++ (as a qualification conversion), but this is still allowed implicitly in C because all pointers can be implicitly converted.
It is written in one book that we cannot change the memory refered by pointer to const like:-
int a = 0, b = 2;
const int* pA = &a; // pointer-to-const. `a` can't be changed through this
int* const pB = &a; // const pointer. `a` can be changed, but this pointer can't.
const int* const pC = &a; // const pointer-to-const.
//Error: Cannot assign to a const reference
*pA = b;
pA = &b;
*pB = b;
Then i written a code to check this and there i had declared pointer to const but changed its memory location and it got run but it should give error ->
#include <iostream>
int main()
{
int a=12;
const int* ptr;
ptr = &a;
std::cout<<*ptr<<"\n";
std::cout<<ptr<<"\n";
std::cout<<*ptr<<"\n";
int b=20;
ptr=&b;
std::cout<<*ptr;
return 0;
}
First let's understand what is the meaning of
const int *p;
The line above means that p is a pointer to a const integer. It means that p is holding the address of a variable which is of 'const int' type. This simply means that you can change the value of pointer 'p'. But the variable whose address 'p' is holding can't be changed because it is of const int type. Now, if you do
int* const p;
it means that the pointer now is of const type and is holding the address of an integer variable. So, here the pointer can't be changed but the value of the variable it is pointing to can be.
Read the comment from the code again:
const int* pA = &a; // pointer-to-const. `a` can't be changed through this
It doesn't say that the pointer cannot be changed. It is the pointed object that cannot be changed (through the pointer). a is the object being pointed by pA.
i had declared pointer to const but changed its memory location and it got run but it should give error
It shouldn't "give" error. You can change a 'pointer to const' i.e. you can make it point to another object. What you couldn't change is a const pointer. But your pointer isn't const.
If you are expecting your code should give error; change prt declaration to -
int* const ptr;
Refer this link it will help you understand in more details Clockwise/Spiral Rule
I'm just starting to learn about C++, so forgive me if this is obvious. What is the difference between the below pointers?
const int i = 42;
constexpr const int *p = &i;
const int const* p2 = &i;
To me, it seems like they are both constant pointers to a constant int. Is there a difference? When would I use each type of declaration?
Thanks :)
1)Meaning of constexpr int *p = &i;
p is const: it cannot be reassigned
i can be modified through p
2)Meaning of const int *p2 = &i;
p2 is non-const: it can be reassigned to point to a different int
i cannot be modified through p2 without use of a cast
This code is invalid C++ and in most cases won't even compile.
You were probably interested in this article:
What is the difference between const int*, const int * const, and int const *?
All three declarations
const int const* p2 = &i;
const int * p2 = &i;
int const* p2 = &i;
are just different ways to write the same thing: a (non-const pointer) to (const int). Most compilers will balk when it's declared like in your code through, because it's not a standard C++ and a likely error.
You will be able to write
p2 = p3; // assign value of (pointer p3) to (pointer p2)
because (pointer) is not const, but not
*p2 = *p3; // assign (object) pointed by (pointer p3) to (object) pointed by (pointer p2)
because (object) that is pointed by a pointer is const (const int in this case)
But if you will write
int * const p2 = &i;
then it'll be a (const pointer) pointing to (int) object. Then things will be completely opposite:
p2 = p3; // don't work
*p2 = *p3; // work!
You can also write const int * const to prohibit both options or don't use const to allow both.
Constexpr is a very different keyword. Rather than say that it's simply a (const object), it says that it's a (const object with value known at compile time). Most "const objects" in C++ are not 'constants' in mathematical sense since they could be different in different runs of same program. They are created at runtime and we just tell compiler that we're not going to change them later. On the other hands, 'constexpr' means that it's a 'real' constant that is defined once and for all. It's always the same and thereby it gets hardcoded in compiled binary code. Since you are beginner, think about it as a fancy C++ version of #define. In your case you tried to declare a pointer to const int to be constexpr, but it won't happen since this pointer is going to be different in different runs of your program and cannot be determined at compile time.
According to a book I'm reading:
we can use a pointer to const to point to a nonconst object:
I tried this:
int i = 42;
int *p1 = &i;
const int *const p3 = 0;
p1 = p3; //error: invalid conversion from 'const int*' to 'int*' [-fpermissive]
Why is this? I tried this with ints and it worked. This is the from the book:
int i = 42;
const int ci = i;
int j = ci;
I thought pointers are objects as well?
A pointer to const is about privileges, not the fundamental type of the pointed-to object.
Essentially, with an int const * (which is the same as const int*), you can look at the int (which may or may not be const itself), but you can't change it. Casting a non-const pointer to a const one allows you to pass a pointer to your own data to a function and not worry that the function might modify it, even though you still can.
To preserve the above dynamic, you can't "get rid" of constness by assigning to another pointer.* That's what your error is saying. That is,
const int * constPtr;
int * nonconstPtr;
*nonconstPtr = 42; // legal
constPtr = nonconstPtr; // legal
*constPtr = 42; // illegal!
nonconstPtr = constPtr; // illegal!
* You actually can cast away constness with const_cast<>. And there are correct uses of the operation. But it is usually very wrong, and you should very probably avoid it.
I'm having problems getting this to work,
class A {
public:
A(int n) {
a = n;
}
int getA() {
return a;
}
private:
int a;
};
int main(){
A* a[3];
A* b[3];
for (int i = 0; i < 3; ++i) {
a[i] = new A(i + 1);
}
void * pointer = a;
b = (A* [])pointer; // DOESNT WORK Apparently ISO C++ forbids casting to an array type ‘A* []’.
b = static_cast<A*[]>(pointer); // DOESN'T WORK invalid static_cast from type ‘void*’ to type ‘A* []’
return 0;
}
And i can't use generic types for what i need.
Thanks in advance.
Arrays are second-class citizen in C (and thus in C++). For example, you can't assign them. And it's hard to pass them to a function without them degrading to a pointer to their first element.
A pointer to an array's first element can for most purposes be used like the array - except you cannot use it to get the array's size.
When you write
void * pointer = a;
a is implicitly converted to a pointer to its first element, and that is then casted to void*.
From that, you cannot have the array back, but you can get the pointer to the first element:
A* b = static_cast<A*>(pointer);
(Note: casting between pointers to unrelated types requires a reinterpret_cast, except for casts to void* which are implicit and from void* to any other pointer, which can be done using a static_cast.)
Perhaps you mean to do
memcpy(b, (A**)pointer, sizeof b);
?
A static_cast version is also possible.