Reputation: 7941
I have a generic list with a template
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;
}
}
};
The important part is the isDelete
This is only a sample code
I need this because I want to store data like this:
GenericList<int> list;
list.add(22);list.add(33);
and also
GenericList<string*> list;
list.add(new string("asd")); list.add(new string("watta"));
The problem if I store only <int>
the compiler said that I cannot delete non pointer variables, but I don't want to in this case. How can I solve this?
when I store <int*>
there is no compiler error...
Upvotes: 0
Views: 1123
Reputation: 361322
Without changing much your code, I would solve your problem as
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;
}
}
};
EDIT: I just noticed that @ildjarn has provided similar solution. However there is one interesting difference: my solution does NOT require you to mention the type of data
when calling the function template; the compiler automatically deduces it. @ildjarn's solution, however, requires you to mention the type explicitly; the compiler cannot deduce the type in his solution.
Upvotes: 3
Reputation: 62975
I would create a nested struct template inside your class to help:
template<typename U>
struct deleter
{
static void invoke(U const&) { }
};
template<typename U>
struct deleter<U*>
{
static void invoke(U* const ptr) { delete ptr; }
};
Then change the line that was using isDelete
from
if (isDelete) { delete tmp->data; }
to
if (isDelete) { deleter<t>::invoke(tmp->data); }
Upvotes: 1
Reputation: 363517
delete
on an int
makes a program ill-formed, so the compiler will reject it, even though the delete
would never be reached.
What you want is only possible if you switch from "bare" pointers to smart pointers such as unique_ptr
or shared_ptr
; those handle memory management for you, without explicit delete
.
Upvotes: 0