【发布时间】:2015-12-16 07:17:42
【问题描述】:
如果您有一个 C 中的函数,该函数对传递给它的任何内容都拥有所有权,例如将struct 按值添加到向量缓冲区的函数,并且此结构值包含指向字符数组的成员指针(一个字符串)。
在缓冲区的清理例程期间,它应该释放它拥有的字符串,但是如果一些字符串是在运行时分配的,而另一些是在编译时使用字符串字面量分配的。
没有安全且标准(非专有)的方法来检测 char* 是否指向只读内存,那么这个假设的 freeVector 函数与指向 char 缓冲区的指针有什么关系?
struct Element {
int id;
char* name;
}
struct Vector {
size_t maxIndex;
size_t length;
struct Element buffer[];
}
void addToVector(struct Vector* vector, struct Element element) {
// lazy-reallocation logic here if maxIndex => length
vector->buffer[ vector->maxIndex++ ] = element; // by-value copy
}
void freeVector(struct Vector* vector) {
for(size_t i = 0; i < vector->maxIndex; i++ ) {
free( vector->buffer[ i ].name ); // segfault/AV if name is a literal
}
}
【问题讨论】:
-
您的元素结构需要一个标志,让您知道是否可以释放该名称。
-
@AlexisWilke 很好,是的,但我想知道是否有更好的方法。
-
有一些专有的方法可以知道指针是在堆中还是在启动数据中,但它可能会更慢(在 Unix 下,它只是一个指针比较,但 Windows 需要 API 调用...... )既然你说“非专有”......
-
您的其他选项是 (1) 在将它们传递给您的数据结构之前始终使用
strdup字符串文字(如果字符串文字很少见,可能会更便宜)或 (2) 在运行时添加垃圾收集器(允许 const 字符串的零拷贝共享)。 -
请注意,字符串文字并不是问题的唯一来源:如果您传递本地字符数组、文件范围 (
static) 或全局字符,则会遇到不同的问题数组到代码。所有这些都不是malloc()和亲戚分配的,因此不能用free()释放。此外,局部变量容易超出范围,并且它们的空间将被重用,从而导致各种问题。到目前为止,最简单的方法是让你的代码始终复制它传递的字符串——决定谁将分配的字符串释放给调用代码。