malloc / free in C ++:为什么free不接受const void *,有更好的方法吗?

时间:2014-05-09 09:44:49

标签: c++ c

将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,因为它告诉我:&#34;无效转换为'const void *'到'void *'[-fpermissive]&#34;

我的第一反应是&#34;呃?你为什么要关心,所有你需要做的就是释放指针。&#34;第二反应是把它扔掉。但这会被编译器拒绝:

free( const_cast<void*>(names) );

这也是如此:

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

E.g。 &#34;从'const char * const *'类型的static_cast无效到'void *'&#34;。

做什么工作是一个很好的&#C;演员:

free( (void*)(acctnames) );

这样安全吗,还是我错过了什么? (valgrind告诉我&#34;所有堆块都被释放 - 没有泄漏可能&#34;,这是一种安慰!)

P.S。在Linux上使用g ++ 4.8.1。

更新:解释为什么free()想要一个非常量指针在这里:Unable to free const pointers in C (虽然我发现barak manos's answer更清楚了。)

2 个答案:

答案 0 :(得分:9)

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足够邪恶,要求它从{{1}获得内存}):

malloc

答案 1 :(得分:2)

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

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

例如:

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

很明显,第一项作业无法应用于const void* p

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