custom iterator for a collection interface - c++

I have an interface ICollection implementing a collection ArdalanCollection like this:
template <typename T>
class ICollection
{
public:
virtual void add(T*) = 0;
virtual T* get(int) = 0;
virtual int count() = 0;
};
template <typename T>
class ArdalanCollection :public ICollection<T>
{
public:
ArdalanCollection() {
index = 0;
};
virtual void add(T* obj) {
encapsolateImplementation.insert(make_pair(index++, obj));
};
virtual T* get(int index) {
return encapsolateImplementation[index];
};
virtual int count() {
return encapsolateImplementation.size();
};
private:
int index;
unordered_map < int, T* > encapsolateImplementation;
};
what I want is to have a generic iterator in ICollection interface which can loop all over the internal container elements(I haven't decided to choose unordered_map as my internal container I might change it to boost or something else). I want to use it in this way:
Node *node1 = new Node(1, 0, 0, 0);
Node *node2 = new Node(1, 0, 0, 0);
ICollection<Node> *nodes = new ArdalanCollection<Node>();
nodes->add(node1);
nodes->add(node2);
for (it=nodes->iterator.begin(); it < nodes->iterator.end(); it++) {
}

First your for loop idiom is not correct. It should rather look like
for(auto it = nodes->begin(); it != nodes->end(); it++)
then something along:
template <typename T, typename MyMap>
class ICollection
{
public:
typedef typename MyMap<int, T *>::iterator iterator;
virtual void add(T*) = 0;
virtual T* get(int) = 0;
virtual int count() = 0;
};
should be fine.

Related

How to declare a class friend to another before its definition

I have those two classes and I want the edge node to be friend for graph but I don't know how to declare it
The implementation of the graph is based on adjacency lists, I used unique_ptr for the auto deletion.
#ifndef GRAPH_HPP
#define GRAPH_HPP
#include <memory>
using std::unique_ptr;
template<typename Type>
class edgenode {
friend class graph<Type>; //here
public:
edgenode(Type w, int adj);
~edgenode() {};
private:
Type mWeight;
int mAdj;
unique_ptr<edgenode<Type>> mNext;
};
template<typename Type>
edgenode<Type>::edgenode(Type w, int adj)
:mWeight(Type), mAdj(adj) {
mNext = nullptr;
}
///-------------------------------------------------///
template<typename Type>
class graph {
public:
graph(int maxvertices = 1000, bool directed = false);
~graph();
private:
unique_ptr<edgenode<Type>>* mEdges;
int* mDegree;
int mNoOfNodes;
int mNoOfVertices;
int mSize;
bool m_bDirected;
};
template<typename Type>
graph<Type>::graph(int maxvertices = 1000, bool directed = false)
: mSize(maxvertices),
m_bDirected(directed),
mNoOfNodes(0),
mNoOfVertices(0)
{
mDegree = new int[mSize];
mEdges = new unique_ptr<edgenode<Type>>[mSize];
for (int i = 0; i < mSize; ++i) {
mDegree[i] = 0;
mEdges[i] = nullptr;
}
}
template<typename Type>
graph<Type>::~graph() {
delete[] mEdges;
delete[] mDegree;
}
#endif
Forward declare the class template like this:
template<typename Type> class graph;
template<typename Type>
class edgenode {
friend graph<Type>;
// ...
Add template class graph<class T>; before edgenode declaration, it's called a forward declaration:
#include <memory>
using std::unique_ptr;
template class graph<class T>; // this
template<typename Type>
class edgenode {
friend class graph<Type>; //here
public:
...

HUGE memory leak when returning std::map<std::string, int> from dereferenced iterator

**Be careful**, not only does this program hang, but apparently it takes all of your memory forever, rendering your computer a slow and awful mess. I've been struggling with this for a real long time, and have figured out a lot of things—except for why it actually hangs. Sorry that there's so much code, but I cut out everything irrelevant and this is what was left.
LinkedList
//=====================
// Linked List
#include <stdexcept>
template<class T> struct LinkedList {
public:
LinkedList();
LinkedList(const LinkedList& srcList);
~LinkedList();
void addObject (T& addedObject);
class ListIterator {
public:
ListIterator();
explicit ListIterator(LinkedList<T>& parentList);
// Operators
ListIterator& operator++();
T& operator*() const;
bool operator!=(const ListIterator& otherIter);
private:
typename LinkedList::Node* current_;
};
ListIterator begin();
ListIterator end();
std::size_t size_;
private:
struct Node {
Node();
Node(T& object);
Node(const Node&) = delete;
T* const object_;
Node* next_;
Node* prev_;
};
Node head_;
Node tail_;
};
//====================
// Classes (Implementation)
// Linked List default constructor
template<class T> LinkedList<T>::LinkedList()
: size_{0} {
head_.next_ = &tail_;
tail_.prev_ = &head_;
};
// Linked List copy constructor
template<class T> LinkedList<T>::
LinkedList(const LinkedList& srcList) {
size_ = srcList.size_;
head_.next_ = &tail_;
tail_.prev_ = &head_;
ListIterator nodesToCopy = srcList.begin();
while (nodesToCopy != srcList.end()) {
this->addObject(*nodesToCopy);
srcList.removeObject(1);
};
delete &srcList;
};
// Linked List destructor
template<class T> LinkedList<T>::~LinkedList() {
for (unsigned int ii = 1; ii == size_; ++ii) {
Node* toDelete = head_.next_;
head_.next_ = head_.next_->next_;
delete toDelete;
};
};
// Add object to Linked List
template<class T> void LinkedList<T>::addObject(T& addedObject) {
Node* node = new Node(addedObject);
node->prev_ = tail_.prev_;
tail_.prev_->next_ = node;
tail_.prev_ = node;
node->next_ = &tail_;
++size_;
};
// Linked List Iterator constructor
template<class T> LinkedList<T>::ListIterator::
ListIterator(LinkedList<T>& parentList) {
current_ = parentList.head_.next_;
};
// Iterator operators
// Increment forward
template<class T> typename LinkedList<T>::ListIterator& LinkedList<T>::
ListIterator::operator++() {
current_ = current_->next_;
return *this;
};
// Return object pointed to
template<class T> T& LinkedList<T>::ListIterator::
operator*() const {
return *(current_->object_);
};
template<class T> bool LinkedList<T>::ListIterator::
operator!=(const ListIterator& otherIter) {
return &(**this) != &(*otherIter);
};
// Return an iterator object via begin() and end()
template<class T> typename LinkedList<T>::ListIterator
LinkedList<T>::begin() {
ListIterator beginIterator(*this);
return beginIterator;
};
template<class T> typename LinkedList<T>::ListIterator
LinkedList<T>::end() {
ListIterator endIterator(*this);
for (unsigned int ii = 0; ii < size_; ++ii) { ++endIterator; };
return endIterator;
};
// Node constructors
template<class T> LinkedList<T>::Node::Node()
: object_(nullptr), next_(nullptr), prev_(nullptr) {};
template<class T> LinkedList<T>::Node::Node(T& object)
: object_(&object) {};
Item
//=====================
// Item
//====================
// Included dependencies
#include <string>
#include <array>
#include <map>
#include <iostream>
class Item {
public:
Item();
Item(std::string name);
Item(std::string name, std::array<int, 2> stats);
std::map<std::string, int> getStats();
std::string name_;
private:
std::map<std::string, int> enhancements_;
};
// Constructors
Item::Item() {
enhancements_["Str"] = 0;
enhancements_["Def"] = 0;
};
Item::Item(std::string name) : Item::Item() { name_ = name; };
Item::Item(std::string name, std::array<int, 2> stats)
: Item::Item(name) {
enhancements_["Str"] = stats[0];
enhancements_["Def"] = stats[1];
};
// Return map of stats
std::map<std::string, int> Item::getStats() { return enhancements_; };
Room
//====================
// Room
class Room {
public:
void addItem(Item item);
LinkedList<Item>::ListIterator getItems();
LinkedList<Item> itemsInThisRoom_;
};
// Add item to room
void Room::addItem(Item item) { itemsInThisRoom_.addObject(item); };
// Get iterator which iterates over items in room
LinkedList<Item>::ListIterator Room::getItems() {
return itemsInThisRoom_.begin();
};
main
int main() {
std::array<int, 2> swordStats = {{5, 0}};
std::array<int, 2> shieldStats = {{0, 2}};
std::array<int, 2> armorStats = {{0, 3}};
Item sword("Sword", swordStats);
Item shield("Shield", shieldStats);
Item armor("Armor", armorStats);
Room room;
room.addItem(shield);
room.addItem(sword);
room.addItem(armor);
LinkedList<Item>::ListIterator roomItems = room.itemsInThisRoom_.begin();
while (roomItems != room.itemsInThisRoom_.end()) {
(*roomItems).getStats();
++roomItems;
};
return 0;
};
All of this can be put in a single file and compiled (I split it up by class to make it easier to read). This is the line, in main, where it hangs:
(*roomItems).getStats();
This leads me to believe there's something wrong with my dereference operator, right? If we create an iterator outside of the Room class, dereference it, and getStats the same way—everything works ok.
... so it's an issue with the Room class?
But, if we change Item and main to the following:
//=====================
// Item
//====================
// Included dependencies
#include <string>
#include <array>
#include <map>
#include <iostream>
class Item {
public:
Item();
Item(std::string name);
Item(std::string, int);
int getStats();
std::string name_;
private:
int enhancements_;
};
// Constructors
Item::Item() {
enhancements_ = 0;
};
Item::Item(std::string name) : Item::Item() { name_ = name; };
Item::Item(std::string name, int stats)
: Item::Item(name) {
enhancements_ = stats;
};
// Return map of stats
int Item::getStats() { return enhancements_; };
//====================
// Room
class Room {
public:
void addItem(Item item);
LinkedList<Item>::ListIterator getItems();
LinkedList<Item> itemsInThisRoom_;
};
// Add item to room
void Room::addItem(Item item) { itemsInThisRoom_.addObject(item); };
// Get iterator which iterates over items in room
LinkedList<Item>::ListIterator Room::getItems() {
return itemsInThisRoom_.begin();
};
int main() {
Item sword("Sword", 1);
Item shield("Shield", 2);
Item armor("Armor", 3);
Room room;
room.addItem(shield);
room.addItem(sword);
room.addItem(armor);
LinkedList<Item>::ListIterator roomItems = room.itemsInThisRoom_.begin();
while (roomItems != room.itemsInThisRoom_.end()) {
(*roomItems).getStats();
++roomItems;
};
return 0;
};
Everything runs excellently. I can return int values alright.
... so... it's neither an issue with the Room class or the dereference operator, but returning std::map? GDB does not have much to say. When I break at the offending line and step, I get:
24 std::map<std::string, int> Item::getStats() { return enhancements_; };
(gdb) step
_Rb_tree_impl (__a=<optimized out>, __comp=..., this=0x7fffffffced0)
at /usr/include/c++/4.9/bits/stl_tree.h:474
474 _M_header(), _M_node_count(0)
(gdb) step
475 { _M_initialize(); }
(gdb) step
_M_initialize (this=0x7fffffffced0)
at /usr/include/c++/4.9/bits/stl_tree.h:484
484 this->_M_header._M_left = &this->_M_header;
(gdb) step
485 this->_M_header._M_right = &this->_M_header;
(gdb) step
_Rb_tree (__x=..., this=0x7fffffffced0)
at /usr/include/c++/4.9/bits/stl_tree.h:674
674 if (__x._M_root() != 0)
(gdb) step
_M_root (this=0x7fffffffd048)
at /usr/include/c++/4.9/bits/stl_tree.h:498
498 { return this->_M_impl._M_header._M_parent; }
(gdb) step
_Rb_tree (__x=..., this=0x7fffffffced0)
at /usr/include/c++/4.9/bits/stl_tree.h:674
674 if (__x._M_root() != 0)
(gdb) step
676 _M_root() = _M_copy(__x._M_begin(), _M_end());
(gdb) step
std::_Rb_tree<std::string, std::pair<std::string const, int>, std::_Select1st<std::pair<std::string const, int> >, std::less<std::string>, std::allocator<std::pair<std::string const, int> > >::_M_copy (
this=this#entry=0x7fffffffced0, __x=0x619f10,
__p=__p#entry=0x7fffffffced8)
at /usr/include/c++/4.9/bits/stl_tree.h:1207
1207 _Link_type __top = _M_clone_node(__x);
... which is gibberish to me. :( It does this infinitely, so I know that it (somehow) describes the hangup.
I've got no clue what's going on here, haha. I'm very new to C++, and have struggled with this since I woke, so for all I know my code is terrible and I should feel bad for writing it.
Any ideas?
In addition to what's already been mentioned, your Node object nonchalantly stores a pointer an object passed from outside by reference
template<class T> LinkedList<T>::Node::Node(T& object)
: object_(&object) {};
However, the reference arguments you pass to the constructor of Node are actually bound to local variables
template<class T> void LinkedList<T>::addObject(T& addedObject) {
Node* node = new Node(addedObject);
node->prev_ = tail_.prev_;
tail_.prev_->next_ = node;
tail_.prev_ = node;
node->next_ = &tail_;
++size_;
};
void Room::addItem(Item item) { itemsInThisRoom_.addObject(item); };
i.e. the reference is bound to parameter item which is a local variable inside addItem.
That local variable item is destroyed as soon as addItem exits. Your Node::object_ pointers remain pointing nowhere.
Considering the amount of gratuitous copying you perform in your code, it is completely unclear how you managed to come up with the idea to store a pointer to a non-owned object inside your Node (instead of gratuitously copying the entire data into the Node, as you do virtually everywhere else).
Anyway, the memory ownership is completely broken in your code, which leads to object lifetime issues as the one above. You need to design some meaningful memory ownership plan from scratch, and then write your code following that plan. What you have now is nonredeemable mess.
If you want to use pointers and you don't think you're ready to untangle this mess, just use smart pointers and let them handle things for you.
P.S. And drop that nasty habit of placing a ; after each and every }.
From template<class T> LinkedList<T>::LinkedList(const LinkedList& srcList)
delete &srcList;
Really? Just removing this line will improve your code. &srcList is not necessarily an address that has been allocated on the heap. And in any case a copy constructor should not be deleting the original.
From template<class T> LinkedList<T>::~LinkedList()
for (unsigned int ii = 1; ii == size_; ++ii)
This loop has no effect unless the size of the list is one, it should be
for (unsigned int ii = 0; ii < size_; ++ii)

using c++, how do I implement itetator to my own container class so i can use something like std::sort()

i'm trying to learn how to implement iterator functionality in my own container class so i can use something like std::sort()
i've created my own container class. how do i now add iterator functionality, like begin(), end(), ...
template <class T> class MyVector { public:
MyVector() : m_DataPtr(NULL), m_nSize(0), m_nAllocated(0) {}
~MyVector() { delete m_DataPtr; }
size_t Size() const { return m_nSize; }
void PushBack(const T &data);
private:
T *m_DataPtr;
size_t m_nSize;
size_t m_nAllocated; };
//******************************
template <class T> void MyVector<T>::PushBack(const T &data) {
if (m_nSize == m_nAllocated)
{
m_nAllocated = (m_nAllocated+1) *2;
T *tmp = new T[m_nAllocated];
if (!tmp)
return;
// transfer data from ptr to tmp
for (size_t i = 0; i < m_nSize; i++)
tmp[i] = m_DataPtr[i];
// delete[] ptr and set it to tmp
delete[] m_DataPtr;
m_DataPtr = tmp;
}
m_DataPtr[m_nSize++] = data;
}
You may implement begin() and end() by adding this to your class definition.
T* begin() { return m_DataPtr; }
T* end() { return m_DataPtr + m_nSize; }
Your use of contiguous memory allows raw pointers to function as iterators.

Access grandparent virtual method

Well, I have three classes:
template<typename E>
class Iterator {
public:
virtual ~Iterator() {
}
virtual bool hasNext() const = 0;
virtual const E& next() = 0;
};
template<typename E>
class IteratorPtr {
private:
Iterator<E>* iterator;
IteratorPtr(const IteratorPtr<E>&);
IteratorPtr<E>& operator=(const Iterator<E>&);
public:
IteratorPtr(Iterator<E>* it)
: iterator(it) {
}
~IteratorPtr() {
delete iterator;
}
Iterator<E>* operator->() const {
return iterator;
}
};
template<typename E>
class Collection
{
public:
virtual void add(const E & value) = 0;
virtual void add(const Collection<E>& collection);
virtual bool remove(const E& value) = 0;
virtual void clear() = 0;
virtual ~Collection()
{
}
virtual bool isEmpty() const = 0;
virtual int size() const = 0;
virtual bool contains(const E& value) const = 0;
virtual Iterator<E>* iterator() const = 0;
};
void Collection<E>::add(const Collection<E>& collection)
{
for (IteratorPtr<E> i(collection.iterator()); i->hasNext();) {
this->add(i->next());
}
}
Obs: all Set's methods are implemented.
template<typename E>
class Set;
template<typename E>
class SortedSet;
template<typename E>
class SetIterator;
template<typename E>
class SetNode {
private:
friend class Set<E> ;
friend class SortedSet<E> ;
friend class SetIterator<E> ;
SetNode()
: next(NULL) {
}
SetNode(E value)
: value(value), next(NULL) {
}
SetNode(E value, SetNode * next)
: value(value), next(next) {
}
~SetNode() {
}
private:
E value;
SetNode * next;
};
template<typename E>
class SetIterator: public Iterator<E> {
private:
friend class Set<E> ;
SetIterator(SetNode<E> * head)
: node(head) {
}
~SetIterator() {
}
bool hasNext() const {
return node != NULL;
}
const E & next() {
E& value = node->value;
node = node->next;
return value;
}
private:
SetNode<E> * node;
};
template<typename E>
class Set: public Collection<E> {
public:
Set(): numNodes(0), head(NULL) {
}
virtual ~Set() {
clear();
}
virtual void add(const E & value);
virtual bool remove(const E& value);
virtual void clear();
virtual bool isEmpty() const;
virtual int size() const;
virtual bool contains(const E& value) const;
virtual Iterator<E>* iterator() const;
private:
Set(const Set & obj): numNodes(0), head(NULL) {
}
virtual bool contains(const E & value, SetNode<E> * & previ) const;
protected:
int numNodes;
SetNode<E> * head;
};
template<typename E>
class SortedSet: public Set<E> {
private:
virtual bool contains(const E& value, SetNode<E> *& prev) const;
public:
SortedSet(): Set<E>() {
}
virtual void add(const E & value);
virtual ~SortedSet() {
this->clear();
}
};
Set and SortedSet don't implement add methods, cause they should do exactly what Collection::add(const Collection& c) does.
int main() {
Set<int> *s = new Set<int>();
s->add(10);
s->add(30);
s->add(12);
s->remove(10);
if (s->contains(30))
puts("Tem");
SortedSet<int> *ss = new SortedSet<int>();
ss->add(*s);
return 0;
}
but this code get a error in the line "ss->add(*s);", saying: no matching to ‘SortedSet::add(Set&)’
Why is this happening?
Now you've posted all the relevant code, the problem is that you've declared another function with the same name in Set:
virtual void add(const E & value);
This hides anything with the same name in the base class; so Collection::add is not accessible via a reference to Set or any of its subclasses.
To fix it, add a using-declaration to Set, to bring Collection::add into the scope of Set:
public:
using Collection::add;

Template refactoring

Let's imagine we have several type of elements, and we want to create a
'manager' for every type of them. The manager takes care of the
creation, activation/deactivation and removal for any of the elements
(we assume the user will no create/destroy the instances of these elements
without using the manager.
A very simple example of the code would be something like this:
template <class T>
class NonCachedElementMngr
{
public:
NonCachedElementMngr():
rmCounter(0)
{}
~ NonCachedElementMngr()
{
T* element = 0;
if(mElements.size() > 0)
{
typename std::set<T*>::iterator it;
for(it = mElements.begin(); it != mElements.end(); ++it)
{
element = *it;
element->deactivate();
delete element;
}
}
}
T* create()
{
T* element = new T();
element->activate();
mElements.insert(element);
return element;
}
bool release(T* element)
{
bool ret = false;
typename std::set<T*>::iterator it;
it = mElements.find(element);
if(it != mElements.end())
{
element->deactivate();
delete element;
mElements.erase(it);
ret = true;
}
return ret;
}
private:
std::set<T*> mElements;
int rmCounter;
};
Let's imagine now that, for a subgroup of objects,
apart from the basic operation, we need also to do
some caching. For that subgroup of types, we could
define another 'manager' like this:
template <class T>
class CachedElementMngr
{
public:
CachedElementMngr():
rmCounter(0)
{}
~CachedElementMngr()
{
T* element = 0;
if(mElements.size() > 0)
{
typename std::set<T*>::iterator it;
for(it = mElements.begin(); it != mElements.end(); ++it)
{
element = *it;
element->removeFromCache(); // <<<<<<<<<<<<<< Different line
element->deactivate();
delete element;
}
}
}
T* create()
{
T* element = new T();
element->storeInCache(); // <<<<<<<<<<<<<< Different line
element->activate();
mElements.insert(element);
return element;
}
bool release(T* element)
{
bool ret = false;
typename std::set<T*>::iterator it;
it = mElements.find(element);
if(it != mElements.end())
{
element->removeFromCache(); // <<<<<<<<<<<<<< Different line
element->deactivate();
delete element;
mElements.erase(it);
ret = true;
}
return ret;
}
private:
std::set<T*> mElements;
int rmCounter;
};
As obvious, both managers are exactly the same, except for the
three lines marked as so.
How could I refactor this two templates?
We know at compile time if a specific type will be cacheable or not.
Notice there is also a different line in the destructor.
Any feasible proposal (virtual inheritance, template specialization, SFINAE...) would be very welcome.
Factor out that specific behavior into a policy:
#include <set>
struct cached_tag;
struct noncached_tag;
template<typename Tag>
struct ElementMngrCachePolicy;
template<>
struct ElementMngrCachePolicy<cached_tag>
{
template<typename T>
static void removeFromCache(T* const element) { /*impl...*/ }
template<typename T>
static void storeInCache(T* const element) { /*impl...*/ }
};
template<>
struct ElementMngrCachePolicy<noncached_tag>
{
template<typename T>
static void removeFromCache(T* const) { /*do nothing*/ }
template<typename T>
static void storeInCache(T* const) { /*do nothing*/ }
};
template<typename T, typename CachePolicy>
class ElementMngr
{
typedef std::set<T*> elements_t;
public:
ElementMngr() :
rmCounter()
{ }
~ElementMngr()
{
for (typename elements_t::iterator it = mElements.begin(); it != mElements.end(); ++it)
{
T* const element = *it;
CachePolicy::removeFromCache(element);
element->deactivate();
delete element;
}
}
T* create()
{
T* const element = new T();
CachePolicy::storeInCache(element);
element->activate();
mElements.insert(element);
return element;
}
bool release(T* const element)
{
typename elements_t::iterator it = mElements.find(element);
if (it == mElements.end())
return false;
CachePolicy::removeFromCache(element);
element->deactivate();
delete element;
mElements.erase(it);
return true;
}
private:
elements_t mElements;
int rmCounter;
};
template<typename T>
class CachedElementMngr : public ElementMngr<T, ElementMngrCachePolicy<cached_tag> >
{ };
template<typename T>
class NonCachedElementMngr : public ElementMngr<T, ElementMngrCachePolicy<noncached_tag> >
{ };
Use a policy class...
template <class T, typename Policy>
class ElementMngr
{
~ElementMngr()
{
T* element = 0;
if(mElements.size() > 0)
{
typename std::set<T*>::iterator it;
for(it = mElements.begin(); it != mElements.end(); ++it)
{
element = *it;
Policy::cleanup(element);
delete element;
}
}
}
T* create()
{
T* element = new T();
Policy::init(element);
mElements.insert(element);
return element;
}
bool release(T* element)
{
bool ret = false;
typename std::set<T*>::iterator it;
it = mElements.find(element);
if(it != mElements.end())
{
Policy::release(element);
delete element;
mElements.erase(it);
ret = true;
}
return ret;
}
};
Then define two policies, both implementing the init(), cleanup() and release() methods, but one does the extra line, the other doesn't...
EDIT: fixed my pseudo code so that it's more like real code, I wanted to show that you can make Policy depend on T too, and then use for example specialization for specific T, or you don't have to - you can decide how to define the policy....
You have any number of options, but the basic idea is to add polymorphism.
For runtime polymorphism, you have these general choices:
Strategy Pattern
Store functors defining whether or not to use the cache (i.e. with std::function s)
Template method (which has nothing to do with C++ templates)
You could also use compile time polymorphism, as detailed in Nim's answer
For an example, here is template method:
template <typename T>
class ElementManager
{
std::set<T*> mElements;
int rmCounter;
virtual void CacheStore(T& element) = 0;
virtual void CacheRemove(T& element) = 0;
public:
ElementManager():
rmCounter(0)
{}
~ElementManager()
{
T* element = 0;
if(mElements.size() > 0)
{
typename std::set<T*>::iterator it;
for(it = mElements.begin(); it != mElements.end(); ++it)
{
element = *it;
CacheRemove(element);
element->deactivate();
delete element;
}
}
}
T* create()
{
T* element = new T();
CacheStore(element);
element->activate();
mElements.insert(element);
return element;
}
bool release(T* element)
{
bool ret = false;
typename std::set<T*>::iterator it;
it = mElements.find(element);
if(it != mElements.end())
{
CacheRemove(element);
element->deactivate();
delete element;
mElements.erase(it);
ret = true;
}
return ret;
}
}
template <class T>
class CachedElementMngr : public ElementManager<T>
{
virtual void CacheStore(T& element)
{
element->storeInCache();
}
virtual void CacheRemove(T& element)
{
element->removeFromCache();
}
};
template <class T>
class NonCachedElementMngr : public ElementManager<T>
{
virtual void CacheStore(T& element)
{
//Purposely Empty
}
virtual void CacheRemove(T& element)
{
//Purposely Empty
}
};
Specifically from the example, it seems that class CachedElementMngr completely contains all the functionality of class NonCachedElementMngr except those 3 lines mentioned. I would do something like this:
template<typename T>
class NonCachedElementMngr
{
/* put all content of "CachedElementMngr" in your example and below methods */
virtual void removeFromCache(T* p) { /* empty */ }
virtual void storeInCache(T* p) { /* empty */ }
virtual ~NonCachedElementMngr() { /*retain original */ }
};
template<typename T>
class CachedElementMngr : public NonCachedElementMngr<T>
{
// everything is inherited; just add below methods in this class
virtual void removeFromCache(T* p) { p->removeFromCache(); }
virtual void storeInCache(T* p) { p->storeInCache(); }
virtual ~CachedElementMngr() { /*retain original */ }
};
And intead of calling following method as,
p->removeFromCache();
p->storeInCache();
it should be called as
removeFromCache(p);
storeInCache(p);