将void*转换为const void**

3

在 CPP 中,我使用了一个 C 库,其中的一种方法需要用 const void ** 作为参数。

在我的类中,我有一个类型为 void * 的属性。

我尝试通过 function(&my_property) 调用该函数,但编译器报错说它无法将 void ** 转换为 const void **

为了解决这个问题,我使用了一个 const 强制转换,并执行了 function(const_cast<const void *>(&my_property))

我尽可能地避免使用强制转换,想知道是否有一种 "干净" 的方法来避免使用 const 强制转换。


这个函数可以为您提供一个 const void *(通过分配给您的指针),而您想要一个 void *。您必须弹出一个 const,以使类型系统满意,但是您为什么首先想要一个 void * - Quentin
@Quentin 但是为什么类型系统会抱怨呢?我们可以使用 T const* x = (T*) y,但不能使用 T const** x = (T**) y。这是为什么呢? - Timo
1
const void** 是指向 const void* 的非常量指针。隐式的 const 属性只能添加在顶层。你需要对 const void* 取地址。如果你的属性具有 void* 类型,则创建本地变量 const void* ptr = my_property; 并调用函数(&ptr); 但如果它是一种输出参数,那么情况就有点棘手了... - Konstantin Stupnik
哦,这就是我错过并且想不起来的东西......const 并不适用于指针,而是适用于指针指向的对象... - f222
2
假设你可以这样做:T const c; T* a; T const **p = &a; *p = &c;,现在非常量的 a 指向一个常量对象而无需强制转换。 - Quentin
@Quentin 好的例子,谢谢。 - Timo
3个回答

1

假设您有以下代码,为了简化您的情况:

void function(const void **p)
{
    //...
}

int main()
{
    void *my_property;
    function(&my_property);
}

使用const_cast是安全的,我认为它并不是那么不干净,但你有其他选择,其中最好的是将my_property转换为const void*,如果怀疑这可能不是一个选项,你可以使用const void*指针,将其分配给原始的void*

void *my_property;
const void *pp = my_property;
function(&pp);

转换仍然存在,但是它是隐式的。
正如Quentin所非常准确地指出的那样,这没有太多意义,除非它只是为了让编译器“闭嘴”。

如果函数的参数是输出参数,你将会在pp中得到结果,而不是my_property中。 - Konstantin Stupnik
const_cast 本身是安全的,但是如果原始指针实际上是 const 的话,你就需要自己确保不修改指向的内容,否则会导致未定义行为。 - Quentin
@KonstantinStupnik,没错,但是你只需要重新分配它。 - anastaciu
@Quentin,是的,那是真的,我假设这不是OP的情况,但确实需要防范。 - anastaciu

1
适当的解决方案是将my_property转换为const void*。否则,您可能会违反function的契约。

0
如果库期望一个数组的数组,使用强制转换可能无法解决问题。如果你无法检查库源代码,你可以猜测。手动转换是一个安全的解决方案。 使用new_cast_a_to_m()需要在某个时刻删除数组,但不是原始数组;struct X和周围的代码仅用于此示例,new_cast_a_to_m()本身应该适用于您。
#include <iostream>

struct X {
    int a = 0;
};

int c_foo (X ** x){
    return x[4][0].a;
}

template <typename V>
V ** new_cast_a_to_m(V * arr, size_t n){
    V ** nc = new V * [n];
    for(size_t i=0; i < n; i++){
        nc[i] = &arr[i];
    }
    return nc;
}

int main(void){

    X ** arr = new X * [5];
    arr[4] = new X;

    std::cout << "intended c_foo() -> " << c_foo(arr) << std::endl;

    X * brr = new X[5];
    X ** nrr = new_cast_a_to_m(brr, 5);
    std::cout << "casted c_foo() -> " << c_foo(nrr) << std::endl;

    delete [] nrr;
    delete arr[0];
    delete [] arr;

    return 0;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接