Reputation: 35408
I have just discovered the following jewel in the code (the example is very simplified, but the logic is the same):
template <class T>
class garbage_bin
{
private:
garbage_bin<T>(void)
{
}
static garbage_bin<T>* pinstance;
public:
static garbage_bin<T>& instance()
{
if(pinstance == NULL)
{
pinstance = new garbage_bin<T>();
}
return *pinstance;
}
void empty()
{
for(size_t i=0; i<items.size(); i++)
{
free (items[i]);
}
}
void throwIn(T item)
{
items.push_back(item);
}
vector<T> items;
};
and then somewhere in the code (this is just ONE example ... there are thousands like this):
char* r = strdup(src);
garbage_bin<char*>::instance().throwIn(r);
and later somewhere in the code, right before the exit ...
garbage_bin<char*>::instance().empty();
garbage_bin<molecules*>::instance().empty();
garbage_bin<CDatabaseUsers*>::instance().empty();
and so on ...
so as we can see, this implements a garbage bin class, in which you can "throw in" all kind of objects, and at a later stage to avoid the memory leaks you "empty" the garbage bin. But here comes the big bottleneck: In order for this to work properly, you need to know all the classes for which this garbage bin was instantiated in order to empty them...
The most direct solution I was thinking of is to create a map of typeid
calls for the instantiations, and assign the garbage_bin<T>::instance()
to the name however an ancient compiler decided that he does not like this approach.
Obviously, I can make a search through the code to find all the templatizations, but I'm wondering ... is there a simpler way to do this?
Upvotes: 0
Views: 76
Reputation: 20503
I would rather replace garbage_bin<T>
with std::vector<std::unique_ptr<T>>
(or, maybe, std::vector<std::shared_ptr<T>>
).
If you want to restrict the interface, then reimplement garbage_bin<T>
as a wrapper around std::vector<std::unique_ptr<T>>
. In this way, you probably don't need the empty
method since the destructors of std::vector
and std::unique_ptr
will clean-up after themselves. However, if you want to empty the bin before destruction, then implement empty
just calling std::vector::clear
.
I understand that this is not exactly the simplest thing to do (because the OP says there are "thousands" of places to be changed) but a refactoring of this bad design is clearly needed.
Upvotes: 0
Reputation: 476970
You could add a registry for things to be deleted:
Registry registry;
// ...
if (pinstance == NULL)
{
pinstance = new garbage_bin<T>();
registry.add<T>();
}
// ...
registry.clear_all();
For example:
class Registry
{
struct Base
{
virtual ~Base() {}
virtual void clear() = 0;
};
template <typename T> struct Derived : Base
{
virtual void clear() { garbage_bin<T*>::instance().empty(); }
};
std::vector<std::unique_ptr<Base>> targets;
public:
void clear_all() { for (auto & p : targets) { p->clear(); } }
template <typename T> void add()
{
targets.emplace_back(new Derived<T>);
}
};
Upvotes: 0
Reputation: 249123
Garbage bin bin!
class garbage_bin_base;
class garbage_bin_bin {
public:
void throwIn(garbage_bin_base* rubbish) { items.push_back(rubbish); }
void empty() { for (auto item: items) item->empty(); }
private:
vector<garbage_bin_base*> items;
};
class garbage_bin_base {
public:
virtual empty() = 0;
garbage_bin_base() { garbage_bin_bin::instance().throwIn(this); }
};
template <typename T>
class garbage_bin : public garbage_bin_base {
};
Upvotes: 1