я использую Word-Net, старая библиотека 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-> nextss;
traceptr_ds повторяется ВСЕ из них, но я не могу найти способ избежать утечки, даже при использовании миниатюрной тестовой проги.
Спасибо, кто помог, очень ценится.
Я знаю, как решить эту проблему для уникального владельца, используя unique_ptr
отличная особенность, где его управляемый тип становится Deleter::pointer
, вместо T*
, если существует первый тип.
Если у вас нет определения Synset
или любой другой тип SynsetPtr
указывает на проблему с использованием shared_ptr
является то, что он не имеет того же средства переключения управляемого типа, и если вы создаете shared_ptr<SynsetPtr>
конструктор будет ожидать SynsetPtr*
, но ваши функции C API не возвращают этот тип. И я не знаю наверняка, используя shared_ptr<remove_pointer<SynsetPtr>::type>
скомпилируется, если у вас нет определения типа, который разыменовывает SynsetPtr
доходность.
это может быть работа, но я не уверен.
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
s.
Нам нужны 2 отдельных удалителя для разных видов 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::shared_ptr
для этой цели, как вы можете предоставить Deleter использовать, чтобы освободить указатель.
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;
}
Теперь, если они действительно представляют разные вещи, вы можете потратить немного больше усилий и предоставить два типа, которые обертывают каждое использование и предоставляют соответствующий интерфейс. Имеет ли смысл рассматривать оба типа как один и тот же, когда трансверс список и дерево могут быть совершенно разными?