c++中的malloc/free:为什么free不接受const void*,有没有更好的方法?

malloc/free in C++: why does free not accept a const void*, and is there a better way?

本文关键字:free 有没有 更好 void 方法 const malloc 中的 不接受 为什么 c++      更新时间:2023-10-16

将c++ 11代码接口到一些C回调,并且我必须传递const char * const *,即字符串数组。以下是我的代码的精简版本:

int main(int,char**){
  const int cnt = 10;
  const char * const * names =
    static_cast<const char * const *>(malloc( sizeof(char*) * cnt));
  //... allocating names[0], etc. coming soon ...
  the_c_function(names);
  free(names);
  return 0;
}

所以我想出了如何在c++中使用malloc,但我被困在free上,因为它告诉我:"从' const void* '到' void* '的无效转换[-fpermissive]"

我的第一反应是"嗯?你为什么要关心,你所要做的就是释放指针。"第二种反应是把它扔掉。但是这会被编译器拒绝:
free( const_cast<void*>(names) );

free( static_cast<void*>(acctnames) );

。"从' const char* const* '类型转换为' void* '类型无效".

所做的工作是一个很好的'ole C cast:

free( (void*)(acctnames) );

这是安全的,还是我错过了什么?(valgrind告诉我"所有堆块都被释放了——没有泄漏是可能的",这是一些安慰!)

注:在Linux上使用g++ 4.8.1

UPDATE:为什么free()想要一个非const指针的解释在这里:无法释放C中的const指针(尽管我发现巴拉克·马诺斯的回答更清楚)

const_cast只能删除constvolatile限定符;它不能改变指针类型。相反,static_cast可以更改类型,但不能删除顶级限定符。但是,从非const对象指针类型转换为void*是隐式的,因此应该可以工作:

free( const_cast<const char**>(names) );

更棘手的转换,将需要const_caststatic_cast(甚至reinterpret_cast在奇怪的情况下)。

邪恶的C可以结合const_caststatic_cast,所以可以作为两者的快捷方式使用。然而,这是一个坏主意,因为它更危险:如果您指定了错误的类型,那么它将通过reinterpret_cast强制转换,可能导致奇怪的运行时行为,其中更安全的强制转换将在编译时失败。

但是,这里不需要任何强制类型转换:从X*X const*的转换可以隐式地完成,因此只需更改本地指针的类型:

const char ** names = static_cast<const char **>(malloc( sizeof(char*) * cnt));
the_c_function(names); // OK - adds const
free(names);           // OK - no const to remove

最后,由于这是c++,根本不需要在malloc和指针上瞎折腾(除非C API足够邪恶,要求从malloc中分配内存):

std::vector<const char*> names(cnt);
the_c_function(names.data());

为了支持动态内存,堆被实现为内存块的链表,其中列表中的每个块存储列表中下一个块的地址。

调用free(p)时,它将地址p处的值设置为列表中第一个块的地址,然后将列表中第一个块的指针设置为p的值。

例如

:

static void* _head;
...
void free(void* p)
{
    *(int*)p = (int)_head;
    _head = p;
}

显然,第一个赋值不能应用于const void* p

根据堆的实现,这可以应用于第一个块(_head)或最后一个块(_tail)。但是原则是一样的,p不能被假定为const(这意味着它可能指向一个只读内存段)。

相关文章: