Ho un singolo elenco di elementi collegati. Ogni elemento ha un ID univoco (numero intero positivo) e un tipo. Ogni elemento può avere un elemento "sorella", associato al suo ID, che può anche essere nella lista. L'elemento sorella è sempre di tipo fisso e non ha una sorella. L'elemento sorella potrebbe trovarsi in un'altra lista.
Ho una funzione per distruggere un elemento di un certo tipo. Questo esegue alcune operazioni di pulizia sull'elemento e lo rimuove dall'elenco.
Quella funzione di distruzione dovrebbe anche distruggere il suo elemento sorella.
La funzione può anche distruggere tutti gli elementi di un certo tipo, quando è passato ID==-1
.
Attualmente sto utilizzando SLIST di BSD, quindi sembra:
destroy_element(list, type, ID) {
struct elem *item, *tmp_item
SLIST_FOREACH_SAFE(item, list, next, tmp_item) {
if((item->type == type) && (ID==-1 || item->ID == ID) {
cleanup_for_element(item);
if (item->sister_ID != -1) {
destroy_element(item->sister_list, item->sister_ID);
}
SLIST_REMOVE(list, item);
}
}
}
SLIST_FOREACH_SAFE
rende possibile rimuovere l'elem corrente ('item'), ma sfortunatamente questo si bloccherà in alcuni casi, se l'elemento sister è nella stessa lista (es .: list==item->sister_list
) e nel punto sbagliato (in questo caso particolare, se l'elemento sister è subito dopo l'elemento nell'elenco)
Sto cercando un costrutto migliore qui. Per SLIST
in particolare, ma in termini di algoritmo generale.
Modifica :
Mi stavo chiedendo se questa soluzione "walk the list twice" sia sicura:
destroy_element(list, type, ID) {
struct elem *item, *tmp_item
SLIST_FOREACH_SAFE(item, list, next, tmp_item) {
if((item->type == type) && (ID==-1 || item->ID == ID) {
if (item->sister_ID != -1) {
destroy_element(item->sister_list, item->sister_ID);
}
}
}
SLIST_FOREACH_SAFE(item, list, next, tmp_item) {
if((item->type == type) && (ID==-1 || item->ID == ID) {
cleanup_for_element(item);
SLIST_REMOVE(list, item);
}
}
}
Sembra funzionare (cioè: crash è sparito), ma non sono sicuro che sia una garanzia in tutti i casi.