使用C ++ 11中的智能指针包装旧C结构并自动释放它们

我正在使用Word-Net ,一个由普林斯顿大学在九十年代开发的旧C库。 该库是用C语言编写的,只显示标题但不显示其实际实现。

我使用的唯一结构是:

SynsetPtr 

我称之为的两个function是:

 findtheinfo_ds traceptrs_ds 

这两个函数都返回一个SynsetPtr。

但是,当SynsetPtr表示感知列表时,我必须使用它来释放它

 free_syns 

然而,当SynsetPtr用于遍历链表(分层树)时,我必须使用它来释放它

 free_synset 

文档不清楚何时调用哪个,以及为什么。

这很快就成了我的噩梦。 我花了三天时间慢慢地通过泄漏,双重释放,内存分配等工作。

所以我想知道,有没有办法让我绕过这些函数或实际的结构,让C ++管理内存? 理想情况下,当没有更多对它们的引用时,我希望它们是免费的,就像std :: shared_ptr的情况一样。

这是可能的,知道Synset_Ptr没有析构函数,但是必须调用dealloc函数吗?

或者,我可以包围创建(分配)这些结构的两个函数,以某种方式预订对象,并在没有引用它们时销毁它们吗?

我真的很感激任何帮助!

编辑:

这是wn.h中SynsetPtr的确切声明

 /* 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-> nextss;

traceptr_ds迭代所有这些,但我找不到一种方法来避免泄漏,即使使用缩小的测试编程。

感谢无论谁帮助,非常感谢。

我知道如何解决这个问题的独特所有权,使用unique_ptr的漂亮function,其托管类型变为Deleter::pointer ,而不是T* ,如果前一种类型存在。

假设您没有Synset的定义,或SynsetPtr指向的任何类型,使用shared_ptr的问题是它没有相同的切换托管类型的工具,并且如果您创建shared_ptr ,构造函数将期望一个SynsetPtr* ,但您的C API函数不会返回该类型。 我不确定使用shared_ptr::type>是否会编译,如果您没有取消引用SynsetPtr产生的类型的定义。

可能有用,但我不确定。

 std::shared_ptr::type> make_findtheinfo_ds(char *searchstr, int pos, int ptr_type, int sense_num) { return std::shared_ptr::type> (findtheinfo_ds(searchstr, pos, ptr_type, sense_num), free_syns); } std::shared_ptr::type> make_traceptrs_ds(SynsetPtr synptr, int ptr_type, int pos, int depth) { return std::shared_ptr::type> (traceptrs_ds(synptr, ptr_type, pos, depth), free_synset); } 

走向独特的所有权路线,我会做一些工厂函数,返回unique_ptr管理SynsetPtr

对于不同类型的SynsetPtr我们需要2个单独的SynsetPtr

 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 make_findtheinfo_ds(char *searchstr, int pos, int ptr_type, int sense_num) { return std::unique_ptr (findtheinfo_ds(searchstr, pos, ptr_type, sense_num)); } std::unique_ptr make_traceptrs_ds(SynsetPtr synptr, int ptr_type, int pos, int depth) { return std::unique_ptr (traceptrs_ds(synptr, ptr_type, pos, depth)); } 

您可以使用std::shared_ptr来实现此目的,因为您可以提供用于释放指针的删除器。

 std::shared_ptr findTheInfo(...) { std::shared_ptr sp(findtheinfo(...), free_syns); return sp; } std::shared_ptr tracePtrs(...) { std::shared_ptr sp(traceptrs(...), free_synset); return sp; } 

现在,如果它们真的代表不同的东西,您可能需要花费更多的精力并提供两种类型来包装每个用途并提供适当的界面。 在遍历列表时,将两者视为相同类型并且树可能完全不同是否有意义?