Я сделал симпатичный универсальный (т.е. шаблон) List
класс для обработки списков в C ++. Причина в том, что я нашел класс std::list
ужасно уродливым для повседневного использования, и, поскольку я постоянно использую списки, мне нужен новый. Главное улучшение в том, что с моим классом я могу использовать []
, чтобы получить предметы из него. Кроме того, еще предстоит внедрить систему IComparer
для сортировки.
Я использую этот класс List
в OBJLoader
, мой класс, который загружает файлы Wavefront .obj и преобразует их в сетки. OBJLoader
содержит списки указателей на следующие «типы»: трехмерные позиции, трехмерные нормали, координаты текстурных ультрафиолетовых лучей, вершины, грани и сетки. В списке вершин есть объекты, которые должны быть связаны с некоторыми объектами во всех трехмерных позициях, трехмерных нормалях и списках координат текстур. Лица ссылаются на вершины, а сетки - на грани. Таким образом, они все взаимосвязаны.
Для простоты, давайте рассмотрим, что в некотором контексте есть только два списка указателей: List<Person*>
и List<Place*>
. Класс Person
содержит, помимо прочего, поле List<Place*> placesVisited
, а класс Place
содержит поле List<Person*> peopleThatVisited
. Итак, у нас есть структура:
class Person
{
...
public:
Place* placeVisited;
...
};
class Place
{
...
public:
List<People*> peopleThatVisited;
};
Теперь у нас есть следующий код:
Person* psn1 = new Person();
Person* psn2 = new Person();
Place* plc1 = new Place();
Place* plc2 = new Place();
Place* plc2 = new Place();
// make some links between them here:
psn1->placesVisited.Add(plc1, plc2);
psn2->placesVisited.Add(plc2, plc3);
// add the links to the places as well
plc1->peopleThatVisited.Add(psn1);
plc2->peopleThatVisited.Add(psn1, psn2);
plc3->peopleThatVisited.Add(plc3);
// to make things worse:
List<Person*> allThePeopleAvailable;
allThePeopleAvailable.Add(psn1);
allThePeopleAvailable.Add(psn2);
List<Place*> allThePlacesAvailable;
allThePlacesAvailable.Add(plc1);
allThePlacesAvailable.Add(plc2);
allThePlacesAvailable.Add(plc3);
Все сделано. Что происходит, когда мы достигаем }
? Вызываются все dtors, и программа вылетает, потому что она пытается удалить вещи два или более раз.
Дтор моего списка выглядит так:
~List(void)
{
cursor = begin;
cursorPos = 0;
while(cursorPos < capacity - 1)
{
cursor = cursor->next;
cursorPos++;
delete cursor->prev;
}
delete cursor;
}
, где Elem
:
struct Elem
{
public:
Elem* prev;
T value;
Elem* next;
};
и T
- это тип List
.
Что возвращает нас к вопросу: как можно безопасно удалить мои List
классы? Элементы внутри могут быть или не быть указателями, и, если они являются указателями, я хотел бы иметь возможность, когда я удаляю свой List
, указать, хочу ли я удалять элементы внутри или только оболочки Elem
вокруг них. ,
Умные указатели могут быть ответом, но это будет означать, что у меня не может быть List<bubuType*>
, а просто List<smart_pointer_to_bubuType>
. Это может быть хорошо, но опять же: объявление List<bubuType*>
не вызовет ошибок или предупреждений, а в некоторых случаях умные указатели вызовут некоторые проблемы в реализации: например, я мог бы объявить List<PSTR>
для некоторых возвращаемых WinAPI , Я думаю, что получить эти PSTR
внутри умных указателей было бы уродливой работой. Таким образом, решение, которое я ищу, я думаю, должно быть как-то связано с системой освобождения из шаблона List
.
Есть идеи?