用C++11中的智能指针包装旧的C结构并自动释放它们
Wrapping around old C Structures with smart pointers in C++11 and auto-freeing them
我使用的是WordNet,这是普林斯顿大学在90年代开发的一个旧的C库。该库是用C编写的,只显示了头,但没有显示其实际实现。
我使用的唯一结构是:
SynsetPtr
我调用的两个函数是:
findtheinfo_ds
traceptrs_ds
这两个函数都返回一个SynsetPtr。
然而,当SynsetPtr表示一个感知列表时,我必须使用来释放它
free_syns
然而,当SynsetPtr用于遍历链表(层次树)时,我必须使用来释放它
free_synset
文档并不清楚何时调用哪个,以及为什么调用。
这很快就成了我的噩梦。我花了三天时间慢慢地处理泄漏、双重释放、内存分配等问题。
所以我想知道,有没有一种方法可以让我绕过这些函数,或者实际的结构,让C++管理内存?理想情况下,当没有更多引用时,我希望它们是免费的,就像std::shared_ptr的情况一样。
知道Synset_Ptr没有析构函数,但必须调用dealloc函数,这可能吗?
或者,我可以绕过创建(分配)这些结构的两个函数,以某种方式保留对象,并在没有引用的情况下销毁它们吗?
我真的很感激任何帮助!
编辑:
这是SynsetPtr在wn.h 中的确切声明
/* Structure for data file synset */
typedef struct ss {
long hereiam; /* current file position */
int sstype; /* type of ADJ synset */
int fnum; /* file number that synset comes from */
char *pos; /* part of speech */
int wcount; /* number of words in synset */
char **words; /* words in synset */
int *lexid; /* unique id in lexicographer file */
int *wnsns; /* sense number in wordnet */
int whichword; /* which word in synset we're looking for */
int ptrcount; /* number of pointers */
int *ptrtyp; /* pointer types */
long *ptroff; /* pointer offsets */
int *ppos; /* pointer part of speech */
int *pto; /* pointer 'to' fields */
int *pfrm; /* pointer 'from' fields */
int fcount; /* number of verb frames */
int *frmid; /* frame numbers */
int *frmto; /* frame 'to' fields */
char *defn; /* synset gloss (definition) */
unsigned int key; /* unique synset key */
/* these fields are used if a data structure is returned
instead of a text buffer */
struct ss *nextss; /* ptr to next synset containing searchword */
struct ss *nextform; /* ptr to list of synsets for alternate
spelling of wordform */
int searchtype; /* type of search performed */
struct ss *ptrlist; /* ptr to synset list result of search */
char *headword; /* if pos is "s", this is cluster head word */
short headsense; /* sense number of headword */
} Synset;
typedef Synset *SynsetPtr;
/* Primary search algorithm for use with programs (returns data structure) */
extern SynsetPtr findtheinfo_ds(char *, int, int, int);
/* Recursive search algorithm to trace a pointer tree and return results
in linked list of data structures. */
SynsetPtr traceptrs_ds(SynsetPtr, int, int, int);
/* Free a synset linked list allocated by findtheinfo_ds() */
extern void free_syns(SynsetPtr);
/* Free a synset */
extern void free_synset(SynsetPtr);
这基本上就是我所知道的全部。
编辑2:
尽管我使用了下面的两个答案,但不幸的是,函数仍然在泄漏字节。
这种情况似乎只发生在:
traceptrs_ds ( ptr, SIMPTR, ADJ, 0 )
文档中几乎没有关于形容词同义词(-synsa)或其他类型(-synsn,-synsv)的信息。
然而,我只需遵循ptr->ptrlist&;ptr->nexts;
traceptr_ds迭代了其中的ALL,但我找不到避免泄漏的方法,即使在使用缩小的测试程序时也是如此。
感谢所有帮忙的人,非常感谢。
您可以为此使用std::shared_ptr
,因为您可以提供删除程序来释放指针。
std::shared_ptr<Synset> findTheInfo(...) {
std::shared_ptr<Synset> sp(findtheinfo(...), free_syns);
return sp;
}
std::shared_ptr<Synset> tracePtrs(...) {
std::shared_ptr<Synset> sp(traceptrs(...), free_synset);
return sp;
}
现在,如果它们真的代表了不同的东西,您可能需要花费更多的精力,并提供两种类型来包装每个使用并提供适当的接口。当转换列表和树可能完全不同时,将两者视为同一类型有意义吗?
我知道如何使用unique_ptr
的漂亮功能来解决唯一所有权的这个问题,如果前一种类型存在,则其托管类型变为Deleter::pointer
,而不是T*
。
假设您没有Synset
的定义,或者SynsetPtr
指向的任何类型,那么使用shared_ptr
的问题在于它没有切换托管类型的相同功能,如果您创建shared_ptr<SynsetPtr>
,则构造函数将需要SynsetPtr*
,但您的C API函数不会返回该类型。如果没有对SynsetPtr
进行解引用所产生的类型的定义,我不确定使用shared_ptr<remove_pointer<SynsetPtr>::type>
是否会编译。
这个可能有效,但我不确定。
std::shared_ptr<std::remove_pointer<SynsetPtr>::type>
make_findtheinfo_ds(char *searchstr, int pos, int ptr_type, int sense_num)
{
return std::shared_ptr<std::remove_pointer<SynsetPtr>::type>
(findtheinfo_ds(searchstr, pos, ptr_type, sense_num),
free_syns);
}
std::shared_ptr<std::remove_pointer<SynsetPtr>::type>
make_traceptrs_ds(SynsetPtr synptr, int ptr_type, int pos, int depth)
{
return std::shared_ptr<std::remove_pointer<SynsetPtr>::type>
(traceptrs_ds(synptr, ptr_type, pos, depth),
free_synset);
}
按照唯一的所有权路线,我会制作几个返回unique_ptr
管理SynsetPtr
的工厂函数。
我们需要两个不同类型的SynsetPtr
s 的独立删除程序
struct sense_list_del
{
using pointer = SynsetPtr;
void operator()(SynsetPtr p)
{
free_syns(p);
}
};
struct linked_list_del
{
using pointer = SynsetPtr;
void operator()(SynsetPtr p)
{
free_synset(p);
}
};
std::unique_ptr<SynsetPtr, sense_list_del>
make_findtheinfo_ds(char *searchstr, int pos, int ptr_type, int sense_num)
{
return std::unique_ptr<SynsetPtr, sense_list_del>
(findtheinfo_ds(searchstr, pos, ptr_type, sense_num));
}
std::unique_ptr<SynsetPtr, linked_list_del>
make_traceptrs_ds(SynsetPtr synptr, int ptr_type, int pos, int depth)
{
return std::unique_ptr<SynsetPtr, linked_list_del>
(traceptrs_ds(synptr, ptr_type, pos, depth));
}
- 为什么这个 std::queue/指向结构的指针列表直到 List.Size() == 0 才释放内存?
- 包含矢量指针的结构的内存释放问题
- 如何安全地停止 IOCP WSARecv() 任务,并释放 WSAOVERLAPED 结构?
- 我可以使用哪种数据结构来释放连续内存中的内存?
- 释放包含多个向量的结构的内存
- 释放指向保留嵌套变量内存地址的结构的指针
- C++:释放动态数组(结构成员)和指向此结构的指针的方法
- std::unordered_map 如何释放使用 malloc 创建的结构.是否需要对地图进行 2 次查询
- 数据结构中的双重释放或损坏
- 用C++11中的智能指针包装旧的C结构并自动释放它们
- 释放包含STL类的链接列表结构的内存
- 如何在C++中释放结构和对象的数组
- C++在结构初始化后释放内存
- 释放组合结构内存的正确方法
- wlanapi-将WlanFreeMemory释放其WLAN_INTERFACE_INFO数组结构
- C++释放结构使用的所有内存
- 释放包含恶意字符串的 malloc'd 结构
- 如何将shared_ptr与指向不应释放的结构的指针一起使用
- 如何从 Libxml2 库中释放结构 xmlSAXHandler
- 如何释放一个结构体的内存,每次循环迭代的指针