template classes deconstructor without knowing type

Hi, i've written a class template (varList) that takes one type as a template argument.
The class basically allocates a vector of that class.
I then have another class that has a vector of (void) pointers to a number of these classes (varListContainer), which have different types.
The container class has a number of methods that must have a type specified so that the void pointers can be recast to the appropriate subclass type, but i want to write a method that deletes all of the subclasses regardless of which type the class took as a parameter.
At the moment I naively recast the void pointers to Myclass<int> pointers and delete that pointer and it seems to work (look at the function varListContainer::removeall()).
Just wondering if anyone can suggest a better way of doing this or if they can tell me if this naive way is guaranteed to work in all circumstances (i imagine this would be equivalent to saying that the default deconstructor always has the same offset for template class types, regardless of the template parameters).
Here is the source code for inspection:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
class vl
{
public:
    void * ptr;
    std::string vartype;
    vl(void * p_ptr, std::string p_vartype)
    {
        ptr = p_ptr;
        vartype = p_vartype;
    }
};
template <class variabletype>
class varList
{
private:
    std::vector<variabletype> args;
    std::vector<std::string> names;
    std::string vartype;
public:
    void clear()
    {
        args.clear();
        names.clear();
    }
    variabletype Get(std::string p_name)
    {
        int n = 0;
        while (n < args.size())
        {
            if (names[n] == p_name)
            {
                return args[n];
            }
            ++n;
        }
    }
    void Add(variabletype p_arg, std::string p_name)
    {
        args.push_back(p_arg);
        names.push_back(p_name);
    }
    varList()
    {
        vartype = typeid(variabletype).name();
    }    
};

class varListContainer
{
private:
    std::vector<vl> varlists;
public:
    template<class variablereturntype>
    variablereturntype get(std::string p_name)
    {
        int n = 0;
        varList<variablereturntype> * vl_ptr;
        while (n < varlists.size())
        {
            if (varlists[n].vartype == typeid(variablereturntype).name())
            {
                vl_ptr = (varList<variablereturntype>*) varlists[n].ptr;
                return vl_ptr->Get(p_name);
            }
            ++n;
        }
    }
    template<class variableaddtype>
    void addType()
    {
        int n = 0;
        while (n < varlists.size())
        {
            if (typeid(variableaddtype).name() == varlists[n].vartype) return;      //Type already exists in the container
            ++n;
        }
        varList<variableaddtype> * vl_ptr;
        vl_ptr = new varList<variableaddtype>();
        varlists.push_back(vl((void*)vl_ptr,typeid(variableaddtype).name()));
    }
    template<class variableinsertype>
    void add(std::string p_name, variableinsertype p_arg)
    {
        int n = 0;
        varList<variableinsertype> * vl_ptr;
        while (n < varlists.size())
        {
            if (varlists[n].vartype == typeid(variableinsertype).name())
            {
                vl_ptr = (varList<variableinsertype>*) varlists[n].ptr;
                vl_ptr->Add(p_arg, p_name);
            }
            ++n;
        }
    }
    template<class variablecleartype>
    void clear()
    {
        int n = 0;
        varList<variablecleartype> * vl_ptr;
        while (n < varlists.size())
        {
            if (varlists[n].vartype == typeid(variablecleartype).name())
            {
                vl_ptr = (varList<variablecleartype>*) varlists[n].ptr;
                vl_ptr->clear();
                return;
            }
            ++n;
        }
    }
    template<class variableremovetype>
    void remove()
    {
        int n = 0;
        varList<variableremovetype> * vl_ptr;
        while (n < varlists.size())
        {
            if (varlists[n].vartype == typeid(variableremovetype).name())
            {
                vl_ptr = (varList<variableremovetype>*) varlists[n].ptr;
                delete vl_ptr;
                varlists.erase(varlists.begin() + n);
                return;
            }
            ++n;
        }
    }
    void removeall()
    {
        int n = 0;
        varList<int> * vl_ptr;
        while (n < varlists.size())
        {
            vl_ptr = (varList<int>*)varlists[n].ptr;
            delete vl_ptr;
            varlists.clear();
            ++n;
        }
    }
};
well i've ascertained that populating a varlistcontainer and then using removeall to clear it causes a whole lot of memory leakage. I suspect that only the integer types are the only ones being properly deleted. anyone have any ideas how to rewrite the removeall() function to make this work?
i've come up with a plan to get this working which involves using a class to 'translate' to the template type, code is as follows:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class translator
{
public:
    void * ptr;
    std::string vartype;
    virtual void dtor() {}
    virtual std::string print() {}
    virtual void clear() {}
    translator(void * p_ptr, std::string p_vartype)
    {
        ptr = p_ptr;
        vartype = p_vartype;
    }
};

template<class T>
class translatetype : public translator
{
public:
    translatetype(T* p_ptr, void * p_vptr, std::string p_vartype) : translator(p_vptr, p_vartype)
    {
        t_ptr = p_ptr;
    }
    T* t_ptr;
    void dtor()
    {
        t_ptr->~varList();
    }
    std::string print()
    {
        return t_ptr->getall();
    }
    void clear()
    {
        t_ptr->clear();
    }
};


however when the dtor() method is called, the method from the base class is called, and is not overridden by the definition in the derived template class. anyone have any ideas?
i think i have this working now.
Are you trying to make a multi-type container? ( http://cplusplus.com/forum/general/25840/#msg138101 )

(Note that although I forgot to clear my container, it can be easily done by delete-ing each pointer-element.
Since BaseType has a virtual destructor, the right destructor will be called.)

What exactly are you trying to do?
Last edited on
The idea was to have a container class varListContainer that could dynamically store any variable type. for example:

1
2
3
4
varListContainer vlc;
vlc.addtype<int>();
vlc.add<int>("name_of_int", 5)
int i = vlc.get<int>("name_of_int"); // i should be 5 


so here the function addtype adds ints to the container, so that integers can be added using the function add<int> as shown in the following line. Looking at your code on that link it seems to be a similiar idea. I eventually got the destructors working anyway so my container seems to work as it should. the only thing that doesn't really work is the name mangling when using typeid.name() so when you try to print out the contents it looks weird.
I think a map could also be useful here.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include <string>
#include <map>
using namespace std;

struct BaseVar
{
    virtual void * data_ptr() {return 0;}
    virtual void * get_type() {return 0;}
    virtual ~BaseVar(){}

    template <class T>
    bool get(T & v);

    template <class T>
    bool set(const T & v);
};

template <class T>
struct Var: public BaseVar
{
    T data;

    static int type;
    static void * get_type_static() {return &type;}

    virtual void * get_type() {return &type;}
    virtual void * data_ptr() {return &data;}
};

template <class T>
int Var<T>::type;

template <class T>
bool BaseVar::get(T & v)
{
    if (get_type()!=Var<T>::get_type_static())
        return false;

    v=*(T*)data_ptr();
    return true;
}

template <class T>
bool BaseVar::set(const T & v)
{
    if (get_type()!=Var<T>::get_type_static())
        return false;

    *(T*)data_ptr()=v;
    return true;
}

int main()
{
    map<string,BaseVar*> var_map;

    var_map["name"]=new Var<string>;
    var_map["age"]=new Var<int>;

    var_map["name"]->set<string>("Bob");
    var_map["age"]->set<int>(45);

    string s; int n;

    var_map["name"]->get<string>(s);
    var_map["age"]->get<int>(n);

    cout << s << endl;
    cout << n << endl;

    if (!var_map["age"]->get<string>(s))
        cout << "error!" << endl;

    delete var_map["name"];
    delete var_map["age"];

    cout << "\nhit enter to quit..."; cin.get();
    return 0;
}

I think your method is a bit safer, in regard to type safety, so i might actually steal some of your code for my project!
The type erasure technique would work for this.

http://www.cplusplus.com/forum/articles/18756/

It is pretty straightforward.
Topic archived. No new replies allowed.