Home > Software engineering >  Casting a reference to a pointer to a reference to a void*
Casting a reference to a pointer to a reference to a void*

Time:10-21

Is the following well defined behavior?

#include <cstdlib>
#include <iostream>

void reallocate_something(void *&source_and_result, size_t size) {
    void *dest = malloc(size);
    memcpy(dest, source_and_result, size);
    free(source_and_result);
    source_and_result = dest;
}

void reallocate_something(int *&source_and_result, size_t size) {
    // I the cast safe in this use case?
    reallocate_something(reinterpret_cast<void*&>(source_and_result), size);
}

int main() {
    const size_t size = 4 * sizeof(int);
    int *start = static_cast<int*>(malloc(size));

    std::cout << start << ' ' << *start << '\n';
    reallocate_something(start, size);
    std::cout << start << ' ' << *start << '\n';

    return 0;
}
  

The code uses a reinterpret_cast to pass a reference to a pointer and re-allocate it, free it, and set it to the new area allocated. Is this well defined?

In particular A static_cast would work if I did not want to pass a reference, and that would be well defined.

The tag is C , and I'm asking about this code as-is within the C standard.

CodePudding user response:

Is the following well defined behavior?

No, it's not. You can't interpret int * pointer with void * handle, int and void are not similar types. You can convert an int * pointer to void * and back. If your function takes a reference, to do the conversion you need a new temporary variable of type void * to hold the result of the conversion, and then you have to assign it back, like in the other answer https://stackoverflow.com/a/69641609/9072753 .

Anyway, just make it a template, and write nice C code with placement new. Something along:

template<typename T>
void reallocate_something(T *&pnt, size_t cnt) {
    T *dest = reinterpret_cast<T *>(malloc(cnt * sizeof(T)));
    if (dest == NULL) throw ...;
    for (size_t i = 0; i < cnt;   i) {
       new (dest[i]) T(pnt[i]);
    }
    free(static_cast<void*>(pnt));
    pnt = dest;
}

CodePudding user response:

Actually I'm not sure but I feel this is the correct way to do.

#include <iostream>
#include <cstring>

void reallocate_something(void *&source_and_result, size_t size) {
    void *dest = malloc(size);
    memcpy(dest, source_and_result, size);
    free(source_and_result);
    source_and_result = dest;
}

void reallocate_something(int *&source_and_result, size_t size) {
    // Is the cast safe in this use case?
    void *temp = static_cast<void*>(source_and_result);
    reallocate_something(temp, size);
    source_and_result = static_cast<int*>(temp);
}

int main() {
    const size_t size = 4 * sizeof(int);
    int *start = static_cast<int*>(malloc(size));

    std::cout << start << ' ' << *start << '\n';
    reallocate_something(start, size);
    std::cout << start << ' ' << *start << '\n';

    return 0;
}

CodePudding user response:

This is not well defined for void* and int* are not similar. Refer to Type aliasing section here.

Note that pointer round trip via void* like below is well defined. Particularly, there is no type aliasing here.

T* pt = ...;

void* p = pt;

auto pt2 = static_cast<T*>(p);
assert(pt2 == pt);

This is different from following code with type aliasing which is not well defined.

T* pt = ...;

void* p = nullptr;
reinterpret_cast<T*&>(p) = pt; // or *reinterpret_cast<T**>(&p) = pt;

auto pt2 = static_cast<T*>(p);
assert(pt2 == pt);

It follows that your sample code can be revised as below.

void reallocate_something(int *&source_and_result, size_t size) {
    void* p = source_and_result;
    reallocate_something(p, size);
    source_and_result = static_cast<int*>(p);
}

Or better yet

void* reallocate_something(void *source_and_result, size_t size) {
    void *dest = malloc(size);
    memcpy(dest, source_and_result, size);
    free(source_and_result);
    return dest;
}

void reallocate_something(int *&source_and_result, size_t size) {
    source_and_result = static_cast<int*>(reallocate_something(source_and_result, size));
}
  • Related