-6

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);
shd
  • 1,201
  • 4
  • 17
  • 29

2 Answers2

4

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);
Pixelchemist
  • 24,090
  • 7
  • 47
  • 71
  • i see the "trick" you did, but i was hoping for shorter answer to solve the casting issue. but the rvalue answer "solves" the casting by stating no other way to do this. thanks ! – shd Jun 26 '16 at 13:00
  • for ignorant souls like me pls check this link for strict aliasing http://cellperformance.beyond3d.com/articles/2006/06/understanding-strict-aliasing.html – PapaDiHatti Jun 26 '16 at 13:07
  • 2
    This will swap `vpa` and `vpb`, not `pa` and `pb`. What's the point? Could just as well say `void* vpa = pb; void* vpb = pa;`. – n. m. could be an AI Jun 26 '16 at 13:12
  • @n.m. Gr8 observation i think after SWAP_POINTERS call we need to do int* pa = int* (vpa); int* pb = int* (vpb) – PapaDiHatti Jun 26 '16 at 13:25
  • @n.m.: Of course it does. What's your point? The function swaps void pointer references after all. I showed how to call the function properly and not how to swap `pa` and `pb`. I consider the fact that passing `vpa` and `vpb` to `SWAP_POINTERS` will swap `vpa` and `vpb` to be downright obvious. – Pixelchemist Jun 26 '16 at 13:36
  • "The function swaps void pointer references" No, it swaps void *pointers*, niot references to those. OP asks how to make it swap *integer pointers*. – n. m. could be an AI Jun 26 '16 at 13:53
  • @n.m.: Yeah I meant that it swaps the pointer *via* references... and no ...OP actually asks why he cannot pass the pointers to the shown function. It is a XY-problem where I solved Y instead of X but Roddy already solved X and I actually refrain from solving X in this case. – Pixelchemist Jun 26 '16 at 14:09
  • @Kapil Yes, you can swap two integer pointers with four assignments and a function call, but I don't think you really want to. There are simpler ways to do the job. – n. m. could be an AI Jun 26 '16 at 14:10
  • @Kapil: The answer merely shows how to call that function with `void&*` arguments fromn `int*` pointers. Swapping pointers would be done via `std::swap` in actual code anyway. – Pixelchemist Jun 26 '16 at 14:21
  • Swapping two pointers `pa` and `pb` means `pa` should assume the value `pb` used to have, and vice versa. Creating some other unrelated pointers like `vpa` and `vpb` with whatever values doesn't solve the problem of swapping `pa` and `pb`. You need to come up with some code that does the equivalent of `int* tmp = pa; pa = pb; pb = tmp;` and preferably be clearer and not much longer that that. If one needs to swap void pointers, `SWAP_POINTERS(vpa, vpb)` barely fits the bill. If swapping int pointers involves tacking temporary variables and assignments on top of that, thanks but no thanks. – n. m. could be an AI Jun 26 '16 at 14:24
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/115644/discussion-between-pixelchemist-and-n-m). – Pixelchemist Jun 26 '16 at 14:38
0

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);
Roddy
  • 66,617
  • 42
  • 165
  • 277
  • 1
    Note this invokes undefined behaviour, so your compiler is allowed to turn you into a newt upon seeing this. – n. m. could be an AI Jun 26 '16 at 14:26
  • @n.m. Is it UB if both `a` and `b` are `int*`? – Roddy Jun 26 '16 at 15:45
  • yes it is. `int*` and `void*` are not even guaranteed to have same size. – n. m. could be an AI Jun 26 '16 at 15:51
  • @n.m.But assigning `int**` to `void*` and back IS guaranteed to work, surely? I've added a version using `static_cast` if that makes you any happier. :) – Roddy Jun 26 '16 at 19:38
  • No, your program cannot be fixed with casts. Assigning int** to void* and back is not the same as taking an address of `int*`, pretending there's a `void*` at that address, **and putting another `void*` there**. Just imagine a machine where `sizeof(int*)==8` and `sizeof(void*)==10`. You have two 8-byte values to swap, and your function swaps two 10-byte values. No matter what casts you use, you cannot change these basic facts. – n. m. could be an AI Jun 26 '16 at 20:06
  • @n.m. But in many cases compiler must do the 8:10:8 thing for you. `int *a;void *v = a; int *b = (int *) v;` If you think that's invalid, how could `malloc`work? – Roddy Jun 26 '16 at 20:36
  • The compiler can deal with it when doing assignment, not when reinterpreting bits. `int i = 7.0;` is OK. `*(double*)&i = 7.0;` is not. It's the same thing here. – n. m. could be an AI Jun 27 '16 at 05:36