正确性和不可变分配对象
在最近的讨论中(参见对这个答案的评论),R ..建议永远不要为指针到const
类型创建别名,因为你无法在一致的C程序中轻松地释放引用的对象(请记住: free()
采用非常量指针参数 和C99 6.3.2.3仅允许从非合格到合格的转换 )。
C语言显然假定任何已分配对象的所有者存在,即某个地方某人必须存储一个非const
指针指向该对象,并且该人负责解除分配。
现在,考虑一个库分配和初始化从用户空间代码不可修改的对象,因此函数调用总是返回const
-qualified指针。
显然,库是对象的所有者,并且应该保留非const
指针,这有点傻,因为用户已经在每个库调用上提供了完全有效但指针的const
副本。
要解除分配这样的对象,库必须丢弃const
限定符; 据我所知,以下内容
void dealloc_foo(const struct foo *foo) { free((void *)foo); }
是有效的C; 如果foo
参数另外restrict
,它将只是无效。
然而,抛弃const
看起来有些黑客攻击。
除了从库函数的所有返回值中删除const
之外还有另一种方法,它会丢失有关对象可变性的任何信息吗?
我在6.3.2.3中没有读到相同的内容。 该段是关于隐式发生并且不需要演员表的转换。 因此,可能不允许从指针到const
对象的隐式转换,但这没有说明显式转换。
转换是在6.5.4中处理的,我没有看到任何会限制你从任何指针到const
,它本身不是const
限定的(void*)
。 恰恰相反
除了6.5.16.1的约束允许之外,涉及指针的转换应通过显式转换来指定。
所以我在那里读到,如果你明确地做事,他们是允许的。
所以我认为以下内容完全有效
char const *p = malloc(1); free((void*)p);
什么6.5.4 forbits将是以下char * const p = malloc(1); 自由((无效*)P); / *的表达式是const限定的* /
作为旁注,对于你的第二行思路,一个返回指针到const
限定对象的库,然后将被置于调用者的责任中,这对我来说没什么意义。 或
- 该库返回一个指向内部对象的指针,然后它应该使它指向
const
指针以获得一些弱调保护,调用者不会改变它,或者 - 库返回一个新分配的对象,该对象属于调用者的责任。 然后它不应该关心调用者是否更改它,因此它可能返回指向非限定对象的指针。 如果调用者想要确保内容不会被意外覆盖,或者他可能会将其分配给
const
指针,供他使用。
如果对象是真正不可变的,为什么要给用户指向它的对象并冒险成为腐败对象的机会? 将对象地址保留在表中,向用户返回一个不透明句柄(整数表索引?)并接受库例程中的句柄。
如果返回const
限定指针,则语义是不允许函数的调用者以任何方式修改对象。 这包括释放它,或将它传递给你的库中的任何function,而这些function将反过来释放它。 是的我知道你可以抛弃const
限定符,但是你违反了const
所暗示的契约。