Удаление общего списка без указателей
У меня есть общий список с шаблоном
template<class t>
class GenericList {
//the data is storeed in a chained list, this is not really important.
struct c_list { t data; c_list* next; ...constructor... };
public:
bool isDelete;
GenericList() : isDelete(false) {...}
void add(t d) {
c_list* tmp = new c_list(d, first->next);
//this is not really important again...
}
~GenericList() {
c_list* tmp = first;
c_list* tmp2;
while(tmp->next!=NULL) {
if (isDelete) { delete tmp->data; } //important part
tmp2=tmp->next;
delete tmp;
tmp=tmp2;
}
}
};
Важной частью является isDelete
Это только пример кода
Мне это нужно, потому что я хочу хранить такие данные:
GenericList<int> list;
list.add(22);list.add(33);
а также
GenericList<string*> list;
list.add(new string("asd")); list.add(new string("watta"));
Проблема, если я храню только <int>
компилятор сказал, что я не могу удалить переменные без указателей, но я не хочу в этом случае. Как я могу решить это?
когда я храню <int*>
нет ошибки компилятора...
3 ответа
Не сильно меняя ваш код, я бы решил вашу проблему как
template<class t>
class GenericList
{
//same as before
//add this function template
template<typename T>
void delete_if_pointer(T & item) {} //do nothing: item is not pointer
template<typename T>
void delete_if_pointer(T* item) { delete item; } //delete: item is pointer
~GenericList() {
c_list* tmp = first;
c_list* tmp2;
while(tmp->next!=NULL) {
delete_if_pointer(tmp->data); // call the function template
tmp2=tmp->next;
delete tmp;
tmp=tmp2;
}
}
};
РЕДАКТИРОВАТЬ: я только что заметил, что @ildjarn предоставил аналогичное решение. Однако есть одно интересное отличие: мое решение НЕ требует упоминания типа data
при вызове шаблона функции; компилятор автоматически выводит это. Однако решение @ ildjarn требует явного упоминания типа; компилятор не может определить тип в своем решении.
Я хотел бы создать вложенный шаблон структуры внутри вашего класса, чтобы помочь:
template<typename U>
struct deleter
{
static void invoke(U const&) { }
};
template<typename U>
struct deleter<U*>
{
static void invoke(U* const ptr) { delete ptr; }
};
Затем измените строку, которая использовала isDelete
от
if (isDelete) { delete tmp->data; }
в
if (isDelete) { deleter<t>::invoke(tmp->data); }
delete
на int
делает программу некорректной, поэтому компилятор отклонит ее, даже если delete
никогда не будет достигнут
То, что вы хотите, возможно, только если вы переключаетесь с "голых" указателей на умные указатели, такие как unique_ptr
или же shared_ptr
; те, которые управляют памятью для вас, без явного delete
,