我刚接触使用Core Foundations。我想使用字典来存储一些键值对。该值必须是指向结构的指针。该指针指向动态分配的缓冲区。
CFMutableDictionaryRef init_hash_table() {
return CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
}
这用于创建字典,返回值存储为全局变量。
CFNumberRef
create_hash_key(int sd) {
return CFNumberCreate(NULL, kCFNumberIntType, &sd);
}
int
add_hash_entry(CFMutableDictionaryRef dict, int sd, void *pkt) {
CFNumberRef key = create_hash_key(sd);
CFDictionarySetValue(dict, key, pkt);
return 0;
}
当我执行此代码时,我会遇到段错误。我看到pkt有一个有效的地址,似乎创建了密钥。有谁知道如何指定一个指向值部分的指针?
程序收到信号EXC_BAD_ACCESS,无法访问内存。 原因:KERN_INVALID_ADDRESS位于地址:0x0000000000000011 objc_msgSend_fixup()中的0x00007fff8c9f339f
有什么想法吗?
答案 0 :(得分:3)
问题是kCFTypeDictionaryValueCallBacks
参数。来自文档:
kCFTypeDictionaryValueCallBacks
包含一组的预定义CFDictionaryValueCallBacks
结构 适用于CFDictionary
中的值时使用的回调 所有CFType
- 派生对象。
因此,在您的情况下,当值添加到指针时,会在指针上调用CFRetain()
字典。这会导致崩溃,因为指针不指向CoreFoundation
对象
您可以使用
创建字典CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, NULL);
相反,所以不会对值进行“引用计数”。
或者,您可以将指针包装到CFDataRef
并将其放入。{}
字典。
在这两种情况下,指针仍然有效是您的责任 当稍后从字典中检索到值时。
以下是一个简单示例,说明如何为自定义对象实现引用计数:
typedef struct {
int refcount;
int val;
} mystruct;
const void *myretain(CFAllocatorRef allocator, const void *value)
{
mystruct *p = (mystruct *)value;
p->refcount++;
return p;
}
void myrelease(CFAllocatorRef allocator, const void *value)
{
mystruct *p = (mystruct *)value;
if (p->refcount == 1)
free(p);
else
p->refcount--;
}
int main(int argc, const char * argv[])
{
mystruct *p = malloc(sizeof(*p));
p->refcount = 1;
p->val = 13;
CFDictionaryValueCallBacks vcb = { 0 , myretain, myrelease, NULL, NULL };
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 0, &kCFTypeDictionaryKeyCallBacks, &vcb);
int sd = 13;
CFNumberRef key = CFNumberCreate(NULL, kCFNumberIntType, &sd);
CFDictionarySetValue(dict, key, p);
// refcount == 2
myrelease(NULL, p);
// refcount == 1
mystruct *q = CFDictionaryGetValue(dict, key);
// refcount is still 1, "GetValue" does not increment the refcount
CFRelease(dict);
// object is deallocated
return 0;
}