将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更清楚了。)
答案 0 :(得分:9)
const_cast
只能删除const
和volatile
限定符;它无法改变指针类型。相反,static_cast
可以更改类型,但无法删除顶级限定符。但是,从非const对象指针类型转换为void*
是隐式的,因此这应该有效:
free( const_cast<const char**>(names) );
更棘手的转化,在奇怪的情况下需要const_cast
和static_cast
(甚至reinterpret_cast
。
邪恶的C演员可以将const_cast
和static_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
(意味着它可能指向只读内存段)。