Прежде всего, я бы не рекомендовал использовать GLib в базе кода C ++; GLib - это библиотека C, полная идиоматического c C кода и функциональности. Вместо этого я бы предложил использовать стандартную библиотеку C ++.
GList
- это двусвязный список, каждый элемент которого состоит из трех указателей:
typedef struct _GList GList;
struct _GList
{
void *data; // untyped pointer data
GList *prev; // pointer to the previous element in the list
GList *next; // pointer to the next element in the list
}
Для удобства все функции GList
принимают NULL
в качестве допустимого списка; в случае g_list_append()
передача списка NULL
в качестве первого аргумента означает, что он выделит новый элемент GList
для передаваемых данных и поместит его в начало списка.
В своем коде вы берете заголовок списка после его заполнения и вызываете g_list_first()
, что является запретом в начале списка; затем вы продолжаете использовать его, перебирая его, пока не дойдете до конца списка, где вы присваиваете nullptr
переменной stack
. Поскольку nullptr
/ NULL
является действительным пустым GList
, теперь вы вызываете g_list_last()
для действительного, но пустого списка, который вернет NULL
и, таким образом, не позволит вам выполнить итерацию в обратном направлении. Кроме того, теперь вы теряете память, выделенную для списка.
Решение состоит в том, чтобы никогда не повторять GList
с той же переменной, которая содержит заголовок списка:
cout << "Printing the stack forward:\n";
GList *iter = g_list_first(stack);
while (iter != nullptr) {
cout << GPOINTER_TO_INT(iter->data);
cout << "->";
iter = iter->next;
}
cout << "nullptr" << endl;
Приведенный выше код будет использовать переменную iter
вместо stack
. Это означает, что приведенный ниже код:
cout << "Printing the stack backward:\n";
iter = g_list_last(stack);
while (iter != NULL) {
cout << GPOINTER_TO_INT(iter->data);
cout << "->";
iter = iter->prev;
}
cout << "nullptr" << endl;
будет работать надлежащим образом и перемещаться по стеку назад, поскольку переменная stack
по-прежнему указывает на начало списка, и теперь вы используете временный итератор .
Не забудьте вызвать g_list_free()
в списке, чтобы высвободить все ресурсы, выделенные для него, и g_list_free_full()
в случае, если вы также выделяете содержимое указателя data
.