Im trying to make a class to use in a Library, and im not sure if its even possible to do. The idea of this class, is to provide methods to insert, search and delete items on a list, but my main problem is that, as i dont know the type of object that i want to place in a list, I dont know how to work with it. I thought I could place a void pointer, and then make it point to a structure, but I havent been able to make it work.
Lets suppose my class is something like this:
class ListManager
{
private:
void* FirstItem;//This would point to the first item of the list
void* LastItem;//This would point to the last item of the list
public:
void AddItemToList(void* Item);
void RemoveItemFromList(void* Item);
}
So, the idea would be that, from my program, I can define a structure like
struct Employee
{
*char Name;
int Id;
int PhoneNumber;
}
And then, use this class, to be able to add/delete Employees. So in this case, the void* pointers, should be pointing to a struct of the type Employee. Nevertheless, i want to make my class work for any type of struct.
I dont know if i explained exactly what I want to do, I tried several ways of doing this, and failed on all of them.
Im going to post a code of how I would like the class to work, if I havent explained myself correctly
ListManager *Worker;
Worker=new(ListManager);
Employee *Item;
Item=new (Employee);
Item->Id=126;
Item->PhoneNumber=42154872;
Worker->AddItemToList(Item);
/*At this point, FirstItem and LastItem should point to the Item i just created*/
Could someone point me in the right direction, as how to make a class work with a structure, without knowing the type of structure?
Thanks in advance
You need templates!
here's a simple interface that you can start working with.
template <typename T>
class ListManager
{
public:
void addItemToList(const T& item);
void removeItemFromList(const T& item);
}
Now T is your type, and you'd declare a ListManager like this:
ListManager<Employee> manager;
I would suggest you also to look at the stl documentation/implementation of a list at: http://www.cplusplus.com/reference/list/list/
You have also the concept of iterators to dig into.
Also, try to use values instead of pointers. With the interface I gave you, you would store the actual value in the list and not a pointer, so the list owns the object and you won't need to manage your memory manually.
See this Tutorial:
http://www.tutorialspoint.com/cplusplus/cpp_templates.htm
Your Example could be look like:
#include <iostream>
using namespace std;
template <class T>
class ListManager
{
private:
void* FirstItem;//This would point to the first item of the list
void* LastItem;//This would point to the last item of the list
public:
void AddItemToList(const T& Item){
std::cout << Item << std::endl;
};
void RemoveItemFromList(const T& Item){};
};
int main() {
ListManager<std::string> mgr;
mgr.AddItemToList("Test");
return 0;
}
Output:
Test
Working Example:
http://ideone.com/FCAtcJ
There really are no interfaces in C++, but you could use a class template just the same way:
template <typename T>
class ListInterface {
public:
void add(T * item) { list.push_back( item); }
void remove(T * item) { list.erase(std::find(list.begin(), list.end(), item)); }
T * get(int index) { return list[index]; }
int size() const { return list.size(); }
private:
std::vector<T *> list;
};
class Manager : public ListInterface<Employee> {
// ...
};
Naturally, this is a barebone example, you really outta do some checking in the remove() and get() methods.
There are multiple solutions to this problem.
Simply use std::list
std::list<Employee> manager;
If 1. is not possible you can define your own list interface using template
template <class T>
class ListManager
{
private:
class Iterator {
public:
T& item;
Iterator* next;
Iterator* prev;
Iterator(T& i, Iterator* n, Iterator* p) : item(i), next(n), prev(p) {}
}
Iterator* FirstItem = NULL;//This would point to the first item of the list
Iterator* LastItem = NULL;//This would point to the last item of the list
public:
void AddItemToList(T& Item) {
if(LastItem) {
Iterator* it = new Iterator{Item, NULL, LastItem};
LastItem->next = it;
LastItem = it;
} else {
Iterator* it = new Iterator{Item, NULL, NULL};
FirstItem = it;
LastItem = it;
}
}
void RemoveItemFromList(const T& Item) {
for(Iterator* it = FirstItem; it != NULL; it = it->next) {
if(it->item == Item) {
if(it->prev)
it->prev->next = it->next;
else
FirstItem = it->next;
if(it->next)
it->next->pref = it->pref;
else
LastItem = it->pref;
delete it;
break;
}
}
}
};
If 1. and 2. is not possible because you need need multiple types inside your list. You can either use a list of Anys (like boost::Any) or a unsafe version with void*:
class ListManager
{
private:
class Iterator {
public:
void* item;
Iterator* next;
Iterator* prev;
Iterator(void* i, Iterator* n, Iterator* p) : item(i), next(n), prev(p) {}
}
Iterator* FirstItem = NULL;//This would point to the first item of the list
Iterator* LastItem = NULL;//This would point to the last item of the list
public:
template<class T>
void AddItemToList(T& Item) {
if(LastItem) {
Iterator* it = new Iterator{&Item, NULL, LastItem};
LastItem->next = it;
LastItem = it;
} else {
Iterator* it = new Iterator{&Item, NULL, NULL};
FirstItem = it;
LastItem = it;
}
}
template<class T>
void RemoveItemFromList(const T& Item) {
for(Iterator* it = FirstItem; it != NULL; it = it->next) {
if(it->item == &Item) {
if(it->prev)
it->prev->next = it->next;
else
FirstItem = it->next;
if(it->next)
it->next->pref = it->pref;
else
LastItem = it->pref;
delete it;
break;
}
}
}
};
Code is not tested
Related
I have the following tree structure:
template<typename T>
class Tree : public std::enable_shared_from_this<Tree<T>>
{
public:
Tree(T data);
Tree(T data, std::vector<std::shared_ptr<Tree<T>>> children);
void add_child(std::shared_ptr<Tree<T>>& child);
void add_children(std::vector<std::shared_ptr<Tree<T>>> children);
void set_parent(std::shared_ptr<Tree<T>> parent)
{ this->parent = parent; }
const T get_data() const
{ return this->data; }
const std::shared_ptr<Tree<T>>& get_parent() const
{ return this->parent; }
const std::vector<std::shared_ptr<Tree<T>>>& get_children() const
{ return this->children; }
private:
T data;
std::shared_ptr<Tree<T>> parent=nullptr;
std::vector<std::shared_ptr<Tree<T>>> children;
};
template<typename T>
Tree<T>::Tree(T data): data(data)
{ }
template<typename T>
Tree<T>::Tree(T data, std::vector<std::shared_ptr<Tree<T>>> children): data(data)
{
this->add_children(children);
}
template<typename T>
void Tree<T>::add_child(std::shared_ptr<Tree<T>>& child)
{
this->children.push_back(child);
child->set_parent(this->shared_from_this());
}
template<typename T>
void Tree<T>::add_children(std::vector<std::shared_ptr<Tree<T>>> children)
{
for (auto&& child : children)
{
this->children.push_back(child);
child->set_parent(this->shared_from_this());
}
}
And I wand to create a function find:
template<typename T>
generator<std::shared_ptr<Tree<T>>> find(const std::shared_ptr<Tree<T>>& t, T value);
Where you give a Tree and a value and it returns a generator that finds each subtree whose root node contains value. My question is, how would I create this generator in C++? I looked into coroutines, but they seemed overly complex for this(or almost anything). I also tried to think about doing the search with helper static variables, but I couldn't think about a way to code it without accidentally skipping nodes.
Here is a helper code to create a tree:
#include <vector>
#include <memory>
#include <iostream>
#include "tree.hpp"
std::shared_ptr<Tree<int>> create_tree()
{
// init tree and nodes
std::shared_ptr<Tree<int>> tree(new Tree<int>(1));
std::shared_ptr<Tree<int>> leaf1(new Tree<int>(5));
std::shared_ptr<Tree<int>> leaf2(new Tree<int>(4));
std::shared_ptr<Tree<int>> leaf11(new Tree<int>(3));
// construct tree
leaf1->add_child(leaf11);
std::vector<std::shared_ptr<Tree<int>>> v;
v.push_back(leaf1);
v.push_back(leaf2);
tree->add_children(v);
return tree;
}
int main()
{
std::shared_ptr<Tree<int>> tree = create_tree();
return 0;
}
First of all you can't use std::shared_ptr<Tree<T>> type for parent in your class. Since you are creating circular dependencies between std::shared_ptr's and they will never be deleted, thus creating memory leak. You can use plain pointer or std::weak_ptr, later is probably better option for you, to keep unified interface. So, in this case your get_parent() function will look like this:
std::shared_ptr<Tree<T>> get_parent() const
{ return this->parent.lock(); }
Now about generator, it is pretty simply to create one. Yes, you need to keep some state, but in case of a tree there is no much of a state to keep. You can do something like this:
template<typename T>
struct generator {
generator(std::shared_ptr<Tree<T>> t, T v) : value(v), tree(t) {}
std::shared_ptr<Tree<T>> getNext() {
std::shared_ptr<Tree<T>> next = advance();
while (next != nullptr && next->get_data() != value) {
next = advance();
}
return next;
}
private:
std::shared_ptr<Tree<T>> advance() {
if (tree == nullptr) return nullptr;
// Special case for first entry
if (state.empty()) {
// If we don't have children, this is last chance
if (tree->get_children().empty()) {
return std::exchange(tree, nullptr);
}
state.push(0);
return tree;
}
// Going up, till next node, can be few levels
while (state.top() >= tree->get_children().size()) {
state.pop();
tree = tree->get_parent();
if (tree == nullptr) return nullptr;
}
std::shared_ptr<Tree<T>> child = tree->get_children()[state.top()];
if (!child->get_children().empty()) {
// Go deeper
state.top()++;
state.push(0);
tree = child;
return child;
}
state.top()++;
return child;
}
T value;
std::shared_ptr<Tree<T>> tree;
std::stack<size_t> state;
};
You should implement an iterator for a generator class.
Hi I'm trying to implement a simple singly linked list using smart pointers, here is what I have so far, I opted with using C++'s shared_ptr but I read that a unique_ptr would be more appropriate for this case but, I don't really know how you would iterate over the list (i.e currentNode = currentNode->next) to get to the end of the list in order to insert an element using a unique_ptr. Here is the code I have so far:
template <typename T>
class LinkedList;
template <typename T>
class ListNode
{
public:
ListNode() : _data(T()) {}
explicit ListNode(const T& value) : _data(value) {}
friend class LinkedList < T > ;
private:
T _data;
shared_ptr<ListNode<T>> _next;
};
template <typename T>
class LinkedList
{
public:
void push_back(const T& value)
{
if (_root)
{
shared_ptr<ListNode<T>> currentNode(_root);
while (currentNode->_next != nullptr)
{
currentNode = currentNode->_next;
}
currentNode->_next = make_shared<ListNode<T>>(value);
}
else
{
// If the list is completely empty,
// construct a new root (first element)
_root = make_shared<ListNode<T>>(value);
}
}
void print() const
{
shared_ptr<ListNode<T>> currentNode(_root);
while (currentNode != nullptr)
{
cout << currentNode->_data << " ";
currentNode = currentNode->_next;
}
cout << endl;
}
private:
shared_ptr<ListNode<T>> _root;
};
If using unique_ptrs are the better way to go for this program, could you illustrate how I would get past the iterating problem? Since unique_ptrs can't be assigned, how would I do the code block:
shared_ptr<ListNode<T>> currentNode(_root);
while (currentNode->_next != nullptr)
{
currentNode = currentNode->_next;
}
currentNode->_next = make_shared<ListNode<T>>(value);
using unique_ptrs instead of shared_ptrs? Thanks!
Your loop with std::unique_ptr may look like:
// Iteration doesn't own resource, so no unique_ptr here.
ListNode<T>* currentNode(_root.get());
while (currentNode->_next != nullptr)
{
currentNode = currentNode->_next.get();
}
currentNode->_next = make_unique<ListNode<T>>(value);
As far as I can understand, linked list can only implemented with an outsider class. Because a class can't have a member varable of it's own type and a node list need that type. The problem is, if the link is intented to be used by a specific class. If, the link class created outside, it will be available to be created as a standalone object.
It's okay if the link class/struct is a pure link object because it can be used for linking another object type. But, in case I need a link that has a functionallity that only related to a certain object, the public availability of it will be pointless. And I think it's better to be created as a private.
Let's take a look at this declaration:
#include <unordered_map>
using namespace std;
template<class T>
class Node
{
public:
Node();
Node(const T& item, Node<T>* ptrnext = NULL);
T data;
// access to the next node
Node<T>* NextNode();
// list modification methods
void InsertAfter(Node<T>* p);
Node<T>* DeleteAfter();
Node<T> * GetNode(const T& item, Node<T>* nextptr = NULL);
private:
Node<T> * next;
unordered_map<string, T*> nodeList;
};
The unordred_map<string,T*> member can only have meaning with a certain object. So, it will be pointless for Node class to be available outside.
Is it possible? Or maybe is it a bad idea to add a non-generic funtionallity for link class?
class A {
A* m_pnext = nullptr;
public:
inline A* next() { return m_pnext; }
inline void set_next(A*ptr) { m_pnext = ptr; }
}
template <class type>
class LinkedList {
type *m_pfirst = nullptr;
public:
void add(type * ptr) {
if ( nullptr == m_pfirst ) {
m_pfirst = ptr;
} else {
type * n = m_pfirst, p = m_pfirst->next;
while (nullptr != p) {
n = p;
p = n->next();
}
n->set_next(ptr);
}
}
};
Plenty of room for improvement, of course. I'll let you exercise your mind.
I am creating a class LinkedList. I am having difficulty adding another node to my list.
Here is what I have so far:
template<typename T>
class LinkedList
{
private:
T element;
T *next;
public:
LinkedList();
LinkedList(T element);
void add(LinkedList<T> &otherList);
void print();
};
template<typename T>
LinkedList<T>::LinkedList()
{
next = NULL;
}
template<typename T>
LinkedList<T>::LinkedList(T element)
{
this->element = element;
next = NULL;
}
template<typename T>
void LinkedList<T>::add(LinkedList<T> &otherList)
{
next = &otherList;
}
template<typename T>
void LinkedList<T>::print()
{
LinkedList<T> *current = this;
while (current != NULL)
{
std::cout << current->element;
current = current->next;
}
}
int main()
{
LinkedList<std::string> myFirst("First");
LinkedList<std::string> mySecond("Second");
myFirst.add(mySecond);
myFirst.print();
return 0;
}
This works however if I make the change:
void add(const LinkedList<T> &otherList);
template<typename T>
void LinkedList<T>::add(const LinkedList<T> &otherList)
{
next = &otherList; //now an error right here
}
Then I get an error stating:
Assigning to 'LinkedList<std::__1::basic_string<char> > *' from incompatible type 'const LinkedList<std::__1::basic_string<char> > *'
Why is it I get this error?
next is a T*, and you're trying to assign a const LinkedList<T>* to it.
I suppose you meant something like next = &(otherList.element) (though even then I think your list semantics are somewhat broken — elements shouldn't typically be shared by multiple containers unless you're very, very clear about the ownership semantics).
Contrary to your claims, your first program doesn't work either for the same reason.
I have to implement a class that behaves like a map of strings using binary search tree. This is the class I implemented:
template<class T>
class StringMapper {
private:
// Pair
struct Pair {
std::string el1;
T el2;
};
// Nod
struct Node {
Pair* data;
Node* left;
Node* right;
Node()
{
data = new Pair;
}
~Node()
{
delete data;
}
int nod_size()
{
// code here
}
};
Node* root;
public:
StringMapper()
{
root = 0;
}
~StringMapper() {}
void insert(std::string from, const T& to)
{
// code here
}
bool find(std::string from,const T& to) const
{
return find(root, to);
}
bool find(Node* node, const T& value) const
{
// code here
}
bool getFirstPair(std::string& from, T& to)
{
if(root != 0)
{
from = root->data->el1;
to = root->data->el2;
return true;
}
return false;
}
bool getNextPair(std::string& from, T& to)
{
if(root != 0)
{
}
return false;
}
int size() const
{
return root->nod_size();
}
};
To be honest I don't know how to implement the function getNextPair().
If someone could help me I'd appreciate it.
Your interface is an internal iterator. You need to keep some kind of pointer to where you are in the iteration, and set it in getFirstPair().
Once you add this, getNextPair() just goes to the next one. It's somewhat difficult to do this, but that's your assignment, so I leave it to you.
The actual std::map uses an external iterator -- that keeps the state of the iteration separate from the data structure. The major advantage is being able to have more than one simultaneous iteration.
Without just throwing the algorithm for getNextPair, you will need to keep some kind of internal iterator which will point to the "current" pair. Once you got that, in order to figure the algorithm for the next pair draw yourself a tree with some nodes and see how one can find the next node in the tree given any node in the tree.