C++ Is it possible to create a private link between objects? - c++

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.

Related

Linked List, copy list to another list

I'm trying to copy a list into another list.
I have this:
template< typename T > class List {
class Node {
public:
T element;
Node *next;
Node( T a_element, Node * a_suivant = nullptr );
virtual ~Node( void );
};
int _taille;
Node * _first;
Node * _last;
public:
List( void );
virtual ~List( void );
int taille( void );
bool empty( void );
I'm trying to create a function that copies a list (using this) into another list and empty the list in argument. I tried to start with emptying the list first to see if it works but I always get segmentation error.
void copyEmpty( List< T > & a_List ){
Node *c = a_List._last;
while(c!=NULL){
Node *t = c->next;
delete c;
c = t;
if(c==a_List._last) c = NULL;
}
a_List._last = NULL;
}
How can I implement the function using next, _last, _first of the list in use (this) and the list in argument (a_List)?
Above of all, it seems you are a C programmer...
Don't use ( void ) in C++!
Use nullptr instead of NULL! (This might become important for overloaded functions taking pointers if you want to make use of std::nullptr_t, the null pointer type, which is defined as decltype(nullptr))
Use, like #david-c-rankin mentioned, a move constructor, or move operator = for your purpose to be compliant with standard design in C++. At least one of them will also work in your template context you mentioned in a comment.
Now coming to the problem: I don't claim that this is a solution since I'm not sure if a got your question right.
template <typename T>
class List {
class Node {
public:
T element;
Node* next;
Node( const T& a_element, Node* a_suivant = nullptr );
virtual ~Node();
};
int _taille;
Node* _first;
Node* _last;
public:
List();
virtual ~List();
int taille();
bool empty();
};
template <class T>
void copyEmpty( List< T > & a_List ){
for(auto pNode = a_List._first; pNode != a_List._last;){
Node* const pNext{ pNode->next };
delete pNode;
pNode = pNext;
}
delete a_List._last;
a_List._last = nullptr;
a_List._first = nullptr;
}
For now I kept your function name. There is still the need of tackling the privateness of _last etc.
I think in your solution you skip deleting the last one.
Maybe you may add a clear specification what _first, _last and your function are / do respectively.

Should referenced std::shared_ptr be deleted after method goes out of scope?

I am learning smart pointers and what is better to learn it than to implement a simple structure, such as Linked List, on the heap.
I created a linked list structure as follows...
// linked list node definition
#ifndef __LINKED_LIST_NODE_H
#define __LINKED_LIST_NODE_H
class LinkedListNode {
friend class LinkedList;
public:
int m_value;
LinkedListNode * m_pNext;
public:
LinkedListNode();
LinkedListNode(int);
LinkedListNode(const LinkedListNode &);
~LinkedListNode();
};
#endif
// linked list definition
#ifndef __LINKED_LIST_H
#define __LINKED_LIST_H
class LinkedList {
LinkedListNode * m_pHead;
LinkedListNode * m_pTail;
public:
LinkedList();
LinkedList(int);
LinkedList(const LinkedList &);
~LinkedList();
void PrintList() const;
void AddItem(int);
void RemoveItem(int);
LinkedListNode * FindNode(int) const;
LinkedListNode * FindMin() const;
LinkedListNode * FindMax() const;
};
#endif
Here are necessarry methods (constructors and destructors) for both LinkedListNode and LinkedList classes to see, what it looks like (IIRC these should be correct)...
// list node
LinkedListNode::LinkedListNode()
{
m_value = 0;
m_pNext = nullptr;
}
LinkedListNode::LinkedListNode(int value)
{
m_value = value;
m_pNext = nullptr;
}
LinkedListNode::LinkedListNode(const LinkedListNode & copyNode)
{
m_value = copyNode.m_value;
m_pNext = copyNode.m_pNext;
}
LinkedListNode::~LinkedListNode()
{
// not needed, no dynamic allocation
}
// linked list
LinkedList::LinkedList()
{
m_pHead = nullptr;
m_pTail = m_pHead;
}
LinkedList::LinkedList(int value)
{
std::shared_ptr<LinkedListNode>newNode{ new LinkedListNode(value) };
m_pHead = newNode.get();
m_pHead->m_pNext = nullptr;
m_pTail = m_pHead;
}
LinkedList::LinkedList(const LinkedList & copyList)
{
if (copyList.m_pHead == nullptr)
{
m_pHead = nullptr;
m_pTail = m_pHead;
}
else
{
std::shared_ptr<LinkedListNode>NodeResource{ new LinkedListNode(*copyList.m_pHead) };
LinkedListNode * tempNode = NodeResource.get();
m_pHead = tempNode;
while (tempNode->m_pNext != nullptr)
{
std::shared_ptr<LinkedListNode>NodeResourceNext{ new LinkedListNode(*tempNode->m_pNext) };
tempNode->m_pNext = NodeResourceNext.get();
tempNode = NodeResourceNext.get();
}
m_pTail = tempNode;
}
}
LinkedList::~LinkedList()
{
// not needed, allocating using smart pointers
}
Now, the LinkedList class contains AddItem method, whose body is this:
void LinkedList::AddItem(int value)
{
std::shared_ptr<LinkedListNode>newNode{ new LinkedListNode(value) };
if (m_pHead == nullptr) // linked list is empty
{
m_pHead = newNode.get();
m_pTail = newNode.get();
}
else
{
m_pTail->m_pNext = newNode.get();
m_pTail = newNode.get();
}
}
And I don't know why, but when I try to add an item to my linked list, it seems the newNode variable is removed when you get out of scope of the method.
Here is what it looks like when I try to debug the program...
First we start off with en empty linked list
Then inside the AddItem function I get the following results (it looks like the m_pHead and m_pTail corretly point to the newly created newNode on heap.
but when the AddItem() method goes out of scope, this is what I am left with
I thought, std::share_ptr is deleted once nothing references the pointer. In my case newNode is referenced by two pointers, m_pHead and m_pTail. Is it really deleted upon leaving the AddItem() method, or is there a flaw in my code I haven't spotted?
Thank you very much for your input, guys.
You are assigning newNode.get() to a raw pointer (LinkedListNode*) member of your LinkedListNode.
This is incorrect because a shared_ptr (in this case at least) owns the underlying pointer. When it goes out of scope, the associated memory is freed yet your LinkedListNode still has a member to the formerly-allocated memory.
You probably should change the definition of LinkedListNode so that its LinkedListNode* members are shared_ptr<LinkedListNode> instead, ensuring the underlying memory gets referenced as long as your instances live.
Your question is far too long, but I see that you seem not to use std::shared_ptr in an appropriate way. For example,
LinkedList::LinkedList(int value)
{
std::shared_ptr<LinkedListNode>newNode{ new LinkedListNode(value) };
m_pHead = newNode.get();
m_pHead->m_pNext = nullptr;
m_pTail = m_pHead;
} // <-- call of std::shared_ptr::~std::shared_ptr
The newNode will be destroyed at the end of the function body. This will then also delete the object the pointer to which is shared (between exactly one std::shared_ptr), whereby leaving m_pHead with a dangling pointer.
The basic idea of shared_ptr is to share ownership of some resources in such a way that as long as any of the sharing owners is still alive, then so is the resource: the resource is deleted when the last owner dies.
In the vast majority of good code, resources are owned by certain objects, i.e. shared ownership is a rather rare and niche situation. There is definitely no need for it in a simple linked list implementation.
One possible ownership model for the linked list is that each node owns the next node. Then you would have
template<typename T> class list;
template<typename T>
class node {
friend class list<T>;
T m_data;
unique_ptr<node> m_next;
explicit node(T const&value)
: m_data(value) {}
node(T const&value, unique_ptr<node>&&n)
: m_data(value), m_next(n) {}
public:
node*next() { return m_next.get(); }
const node*next() const { return m_next.get(); }
};
template<typename T>
class list {
typedef node<T> node_type;
unique_ptr<node_type> m_head;
node_type *m_tail;
~list() {} // destructor of m_head destroys all nodes recursively
explicit list(T const&value)
: m_head(new node_type(value)), m_tail(m_head.get()) {}
void push(T const&value)
{
// move the existing m_head to be m_next of the new node,
// which in turn becomes the new m_head. m_tail is unaffected.
m_head = new node_type(value,std::move(m_head));
}
};
However, you must be careful how you implement insertion and slicing etc.

Compile error when creating object within linkedlist within pointer array: C++

***UPDATE****
so to start I am trying to attempt hashing. to try to make it short, I created a linkedlsit class which takes in a generic parameter . I have a hashtable class where I attempted to create (i believe) a array of linkedlist pointers (keeping in mind the linkedlist takes a generic type )
so, in my hashtable class, I have a private variable such that
SLL< Entry <string, int> >** list;
where SLL is my linked list, Entry is the object that holds a key (string) and value (int) and tying to make it a array of pointers.
in the hashtable constructor i create it like this
list = new SLL<Entry<string, int> > * [this->size];
now in my code, i attempt to append the Entry object into the array after my hashcode function ends
list[hash]->append(new Entry<string, int>(key, e));
however it get this error
HashTable.h: In member function 'void HashTable::createEntry(std::string, int)':
HashTable.h:78:53: error: no matching function for call to 'SLL<Entry<std::basic_string<char>, int> >::append(Entry<std::basic_string<char>, int>*)'
list[hash]->append(new Entry<string, int>(key, i));
it works if i replace Entry as the object within the linkedlist as jsut an int, or float, or even string
so what can be causing this? please and thank you, if you need any more info, let me know :)
#ifndef SLL_H
#define SLL_H
template <class T>
class SLL
{
private:
Node<T>* head;
Node<T>* tail;
int size;
public:
SLL();
virtual ~SLL();
void append(T&);
void append(T*);
void prepend(T);
void deleteElem(int);
void toString();
int getSize();
void insertAt(T, int);
T retrieveDataAt(int);
};
#endif /* SLL_H */
template <class T>
SLL<T>::SLL()
{
this->tail = NULL;
this->head = NULL;
this->size = 0;
}
void SLL<T>::append(T data)
{
//do stuff
this->head = new Node<T>(data);;
}
There's a couple of issues with the code you posted, and it just goes to show
that when using templates you need to be sure everything matches up nicely.
Especially because the compiler will not even care about some types of errors
until you actually instantiate a template with a certain type.
The first is that your class SLL<T> declares a number of member functions,
two of which are SLL::append(T&) and SLL::append(T*). The problem is that in
the example code you posted, the member function you are defining is
SLL::append(T), which doesn't exist!
The second is that because new returns a pointer to a type, your code:
list[hash]->append(new Entry<string, int>(key, e));
is equivalent to
Entry<string, int>* data_ptr = new Entry<string, int>(key, e);
list[hash]->append(data_ptr);
which will look for a member function of the form SLL::append(T*) not
SLL::append(T), and no such function has been defined!
Here's some minimally working code that should compile for you. Note that I
used std::pair instead of Entry for brevity and that you'll need to compile with a
-std=c++11 or equivalent flag (e.g. g++ -std=c++11 main.cpp) since I used nullptr:
#include <utility>
#include <string>
template<class T>
class SLL;
// singly linked list node
template<class T>
class Node
{
private:
Node<T> *next;
T data;
friend class SLL<T>;
public:
Node(T input) : next(nullptr),
data(input) {}
~Node() {delete next;}
};
// the singly linked list class
template <class T>
class SLL
{
private:
Node<T>* head;
Node<T>* tail;
std::size_t size;
public:
SLL() : head(nullptr),
tail(nullptr), size(0) {}
~SLL() {delete head;}
std::size_t getSize() const {
return size;}
void append(T data);
};
template<class T>
void SLL<T>::append(T data)
{
Node<T> *temp = new Node<T>(data);
if (!head)
head = temp;
if (tail)
tail->next = temp;
tail = temp;
size += 1;
}
int main()
{
// less typing
using list_type = SLL<std::pair<std::string, int>>;
// allocation for the list of lists
std::size_t hash_size = 10;
list_type** list_of_lists = new list_type*[hash_size]();
// data to input
std::string key = "key";
int value = 9330323;
std::size_t hash = 4;
// check and append
if (!list_of_lists[hash])
list_of_lists[hash] = new list_type;
list_of_lists[hash]->append(std::pair<std::string, int>(key, value));
// cleanup
for (std::size_t i = 0; i < hash_size; ++i)
delete list_of_lists[i];
delete[] list_of_lists;
}

C++ pass by reference then set a pointer to the object

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.

Template Friend for Superclass

I have a non-templatized class (Par_list_elem), and I would like to give access to its internals to the class Par_list (to build an intrusive list).
The catch: I need Par_list_elem and all of its subclasses to be accessible to Par_list. In detail, the only fields that need to be accessible are _next and _prev; explicitly limiting to those fields would be nice, but isn't required.
I've made a few preliminary attempts at doing this, the latest of which is below:
template <class T> class Par_list {
public:
Par_list() : _head(0) {}
~Par_list();
//Insert element into list
bool insert(T elem);
//Remove element identified by iterator
void erase(iterator itr);
private:
T* _head;
};
class Par_list_elem {
public:
Par_list_elem() : _next(0), _prev(0) {}
//Get next element in list
Par_list_elem* next() { return _next; }
private:
Par_list_elem* _next;
Par_list_elem* _prev;
template <typename> friend class Par_list;
};
template <class T> void Par_list<T>::erase(Par_list<T>::iterator itr) {
T* e = *itr;
T* p;
if ((p = e->_prev) != 0)
p->_next = e->_next;
else
_head = e->_next;
if ((e->_next) != 0)
(e->_next)->_prev = p;
delete e;
}
template <class T> bool Par_list<T>::insert(T* nelem) {
T* curr = _head;
if (curr != 0) {
while (curr->_next != 0)
curr = curr->next();
curr->_next = nelem;
} else
_head = nelem;
nelem->_prev = curr;
nelem->_next = 0;
return true;
}
test.cpp
#include "parsnip_list_back.h"
class elem : parsnip::Par_list_elem {
int _elem;
};
int main (int argc, char** argv) {
parsnip::Par_list<elem> plist;
return 0;
}
Some information seems to be available here:
Template friend
But the goal is different in enough detail that I'm stuck.
Thanks!
--------UPDATE---------
The following sort of error occurs for each instance of an access of a private member of Par_list_elem. I'm compiling on gcc 4.4.
parsnip_list_back.h:66: error: ‘parsnip::Par_list_elem* parsnip::Par_list_elem::_prev’ is private
parsnip_list_back.h:124: error: within this context
So, with the current implementation, even the superclass isn't giving up its privates.
The problem is that you're inheriting privately from Par_list_elem. So, although Par_list can access private members of the base class, it cannot access the base class itself.
I need Par_list_elem and all of its subclasses to be accessible to Par_list.
This would solve the problem if it were possible, but it can't be done; friendship isn't inherited.
The simplest solution is to inherit publicly.