I'm not sure how to describe this. I have to iterate through objects which are connected by pointers with each other, However the first element shouldn't have values stored in its class just the pointer to the next element.
I came up with a small class hierarchy. If I use it like that I have to cast the base class to the derived element. It only seems to work with a dirty cast.
Is there a better solution?
Here the example code:
#include <iostream>
struct Basenode {
Basenode* next;
};
struct Skipnode : Basenode {
Skipnode(int in_key, int in_value);
int key;
int value;
};
Skipnode::Skipnode(int in_key, int in_value)
: key{ in_key }, value{ in_value }
{
}
int main()
try {
Basenode head; // no key and value
Skipnode first(4, 2); // key and value
Skipnode second(8, 2);
Basenode* p = &head;
head.next = &first; // fine
first.next = &second; // fine
// p = p->next->key; // not accesible because is Basenode not derrived Skipnode
std::cout << static_cast<Skipnode*>(p->next)->key; // fine but diryt cast slicing ?
std::cin.get();
}
catch (std::runtime_error& e) {
std::cerr << e.what() << "\n";
std::cin.get();
}
catch (...) {
std::cerr << "unknown error " << "\n";
std::cin.get();
}
Edit: it was asked int the comments why i need this anyway. I think i gave a to limited example.
I need it to implement a skiplist. Many algorithms of it require to start on a element before the first element. The head element. I could make it a normal node and put in dummy values for the values but it didnt seem right. So now i came up with this ugly solution from youre suggestions to start on the head elements.
Heres a snippet with the copy constructor as example.
class Skiplist {
public:
//...
Skiplist(const Skiplist& other); // copy constructor
//...
private:
struct Skipnode; // forward declaration so Basenode can have Skiplist*
struct Basenode { // Empty node, mainly created to represent head element.
// Is there a way to get a empty head with no key / values without using this ?
Basenode(int in_level);
Basenode(const std::vector<Skipnode*>& in_next);
std::vector <Skipnode*> next;
};
struct Skipnode : Basenode { // derived so with Basenode* we can start the iteration of the node on head
Skipnode(value_type val, int in_level);
Skipnode(value_type val, const std::vector<Skipnode*>& in_next);
value_type value; // first key / second mapped type = value
//key_type key;
//mapped_type value;
};
Basenode head{ 0 }; // element before first element containg pointers to all the first elements of each level
//...
};
Skiplist::Skiplist(const Skiplist& other) // copy constructor
:head{ other.head }, top_level{ other.top_level }, random_engine{ other.random_engine }
// on the first level let the other Skiplist present its elements and make a deep copy of them
// now still the higher levels point to the other node so this is fixed in the second part
// then the next level pointers are installed linked to the elements of the new node
{
if (top_level == 0) return; // no elements are present so dont bother to allocate nodes
{
// installment of lowest level, each element is located here
Skipnode* other_node = other.head.next[0];
Basenode* current_position = &head;
while (other_node != nullptr) {
Skipnode* new_node = new Skipnode{ other_node->value,other_node->next };
current_position->next[0] = new_node;
current_position = current_position->next[0];
other_node = other_node->next[0];
}
current_position->next[0] = nullptr;
}
// installment of the other levels
for (size_type curr = 1; curr < top_level; ++curr) {
Basenode* current_position = &head; // the current position of the level[curr]
Skipnode* next_position = current_position->next[curr]; // next position after curr containing still pointers to the other skiplist
Basenode* lowest_position = &head; // lowest level position used to find the new pointers and attach them "behind" current
while (lowest_position != nullptr && next_position != nullptr) {
if (lowest_position->next[0]->value.first == next_position->value.first) { // check by unique key, address of next pos is still of the other skiplist
current_position->next[curr] = lowest_position->next[0]; // lowest is the valid address of new node
current_position = current_position->next[curr];
next_position = next_position->next[curr]; // go to next element of other node
if (next_position == nullptr) { // case end is reached
current_position->next[curr] = nullptr;
current_position = current_position->next[curr];
}
}
else { // forward position of lowest level until other key == next position key
lowest_position = lowest_position->next[0];
}
}
}
}
See here for a basic explanation how a skiplist is organized:
https://en.wikipedia.org/wiki/Skip_list
The whole code is on codereview:
https://codereview.stackexchange.com/questions/197752/non-generic-skip-list-implementation-in-c-version-2
All the things #SomeProgrammerDude is saying, or:
I don't see a need for class BaseNode at all. Why can't we just have (all other things being equal):
SkipNode *head = &first;
...
Or better yet a class called (for example) SkipNodeList that handles all aspects of managing and iterating through a list of SkipNodes.
Of course, this is all a bit silly anyway, just use std::list (or std::forward_list) for this and benefit from all that STL goodness.
Or you can derive from one of these to add your own functionality (such as a mutex to make the list threadsafe or keeping track of the number of elements currently in the list, as suggested by #iMajuscule).
Yes, there is a better way:
Forward-declare Skipnode, and in BaseNode, use a pointer to SkipNode, this way you don't have to cast:
struct Skipnode;
struct Basenode {
Skipnode* next;
};
Also, to illustrate how this design where Skipnode inherits from Basenode could make sense (related to the discussion in the comments), we can imagine having a member in Basenode counting how many elements are next (counting the one in the next member and its successors)
Related
I am writing a binary tree search program but I'm not sure how to add nodes and search through them. The nodes come from a .txt file that is being read with a different file so just assume that already works.
The text file looks like:
Name Location
Old Building 31.2222
New Building 21.2111
Like I said, the program already reads in the file so that's not an issue. However, I have to insert the name and location into the nodes of the binary tree. Then I have to search everything within a range which is where the plus minus comes from.
Side note: my copy constructor may be incorrect as well though it complies properly.
Thanks for the help!
#ifndef BINTREE_HPP
#define BINTREE_HPP
#include <utility>
#include <string>
#include <vector>
class bintree {
// A binary search tree for locations in Lineland.
// Notes:
// - Assume a flat, one-dimensional world with locations from -180 to 180.
// - All locations and distances are measured in the same units (degrees).
public:
// Default constructor
bintree() {
this->root = NULL;
}
// Copy constructor
bintree(const bintree &t) {
this -> root = NULL;
*this = t;
}
// Destructor
~bintree() {
}
// Copy assignment is implemented using the copy-swap idiom
friend void swap(bintree &t1, bintree &t2) {
using std::swap;
// Swap all data members here, e.g.,
// swap(t1.foo, t2.foo);
// Pointers should be swapped -- but not the things they point to.
}
bintree &operator= (bintree other) {
// You don't need to modify this function.
swap(*this, other);
return *this;
}
void insert(const std::string& name, double p) {
// insert node with name and location (p)
}
void within_radius(double p, double r, std::vector<std::string> &result) const {
// Search for elements within the range `p` plus or minus `r`.
// Clears `result` and puts the elements in `result`.
// Postcondition: `result` contains all (and only) elements of the
// tree, in any order, that lie within the range `p` plus or minus
// `r`.
}
private:
struct node
{
node *left;
node *right;
};
node* root;
};
#endif
First, your nodes need to hold the data:
struct node
{
node *left;
node *right;
std::string name; // This is the key for your reasearch
double p; // followed by other data
};
Then you can think to browsing through your tree to insert a new node.
In this example, I assume that you can insert several nodes with the same name.
void insert(const std::string& name, double p) {
node *n = new node; // create a new node
n->name=name; n->p=p; // intialise the data payload
n->left=n->right=nullptr; // and make it a leaf.
if (root==nullptr) // if tree is empty,
root = n; // add the new node.
else { // else find where to insert it
node* t=root;
while (true) {
if (t->name > n->name) { // go to left
if (t->left==nullptr) {
t->left = n;
break;
}
else t=t->left;
}
else if (t->name == n->name) { // insert between current and next
n->right = t->right;
t->right = n;
break;
}
else { // go to right
if (t->right==nullptr) {
t->right = n;
break;
}
else t=t->right;
}
}
}
}
Here a live demo.
Note that I have only answered your insertion question, you still have to do a lot on your own (operator= and copy constructor need review, a destructor needs to be created, etc...)
Is it possible to create a circular doubly-linked list using smart pointers in C++
struct Node {
int val;
shared_ptr<Node> next;
weak_ptr prev;
};
shared_ptr<Node> head;
But this will have a circular reference of shared pointers and thus not deallocate correctly.
Make the circular linked list a class itself (with whatever operations you need to build it, like append). Have its destructor break the link by setting tail->next = nullptr. It should not matter which link you break, so if you're not using a head and tail, just set any one of them nullptr, and you're good.
In my testing, I made a circular linked list, and the nodes did not destruct. Then at the end, I added tail->next = nullptr before it exited, and all the destructors fired correctly.
My original posted answer was rather light on details. This one gives a proper explanation of how you can achieve a circular linked list without a memory leak and still adhere to the Rule of Zero. The answer is basically the same, using a sentinel, but the mechanism is a little more involved than I had originally let on.
The trick is to use a sentinel type that behaves just like a list node, but in fact does not really have a shared pointer to the head of the list. To achieve this, the node class should be separated into a behavior object and a state object.
class NodeState {
std::shared_ptr<Node> next_;
std::weak_ptr<Node> prev_;
int value_;
NodeState (int v) : value_(v) {}
NodeState (std::shared_ptr<Node> p) : next_(p), prev_(p) {}
//...
};
class Node {
virtual ~Node () = default;
virtual NodeState & state () = 0;
std::shared_ptr<Node> & next () { return state().next_; }
std::weak_ptr<Node> & prev () { return state().prev_; }
int & value () { return state().value_; }
void insert (const std::shared_ptr<Node> &p) {
//...
}
};
Now, you can define a node implementation and a sentinel implementation.
class NodeImplementation : public Node {
NodeState state_;
NodeState & state () { return state_; }
NodeImplementation (int v) : state_(v) {}
//...
};
class NodeSentinel : public Node {
List &list_;
NodeSentinel (List &l) : list_(l) {}
NodeState & state () { return list_.sentinel_state_; }
};
The list itself contains a NodeState used by the sentinel object. Upon initialization, the list creates a sentinel object and initializes its state.
class List {
//...
NodeState sentinel_state_;
std::shared_ptr<Node> head () { return sentinel_state_.next_; }
std::shared_ptr<Node> sentinel () {
return std::shared_ptr<Node>(head()->prev());
}
//...
public:
List () : sentinel_state_(std::make_shared<NodeSentinel>(*this)) {}
//...
void push_front (int value) {
head()->insert(std::make_shared<NodeImplementation>(value));
}
void push_back (int value) {
sentinel()->insert(std::make_shared<NodeImplementation>(value));
}
//...
};
So, what does this organization do? It avoids the issue of a circular reference by using a sentinel node to act as the break. While the tail of the list points to the sentinel object, the sentinel object itself does not point to anything. Instead, it uses the state of the list itself to determine its next and previous neighbors.
Thus, the circular shared pointers only persists as long as the list exists. Once the list is destroyed, Item A loses its reference, and via the domino effect, Sentinel itself will be destroyed.
A fundamental point is that the sentinel object itself must never be exposed to the user of the list interface directly. It should remain internal to the list object at all times. It essentially represents end() in an STL like container, and logically, it can never be removed from the list (until the list itself is destroyed). In practice, this means removal operations on the list need to exit early if the passed in iterator represents the sentinel.
Demo
Try It Online
It is also possible to define a member function next() which can select between a shared or weak pointer.
#include <iostream>
#include <memory>
using namespace std;
struct T {
int n_;
shared_ptr<T> next_;
weak_ptr<T> weaknext_;
T(shared_ptr<T> next, int n) : next_(next), n_(n) {};
auto next() {
if (next_ == nullptr)
return shared_ptr<T>(weaknext_);
return next_;
}
~T() { cout << n_ << "ok\n"; }
};
int main() {
auto p0 = make_shared<T>(nullptr, 1);
auto p1 = make_shared<T>(p0, 2);
auto p2 = make_shared<T>(p1, 3);
p0->weaknext_ = p2; //makes the list circular
auto p = p2;
for (int i = 0; i < 5; ++i) {
cout << p->n_ << "\n";
p = p->next();
}
}
I want to implement a circularly double linked list. this list just includes these chars in a passed in string object
Here is my code, but I always get seg fault. i use a dummy head for this list
#ifndef MY_LIST_H
#define MY_LIST_H
#include <string>
#include <iostream>
using namespace std;
/**------ -----------------
* dummy |->|pred|value|next|
* ------ -----------------
* */
struct Node
{
char value;
Node *next;
Node *pred;
Node( char value): value(value), next(0), pred(0){};
};
class MyList
{
private:
Node* head;
unsigned int count; // count number of node
public:
// default constructor
MyList(): count(0)
{
head = new Node('P');
}
//Constructs a list from a passed-in string object,
MyList(const string& str): count(0)
{
Node *cur = head;
if(count == 0)
{
head-> pred = head;
head-> next = head;
}
else
{
for( unsigned i =0; i< str.length(); ++i)
{
cur->next = new Node(str.at(i));
Node *temp = cur->next;
temp-> pred = cur;
++count;
if(count == str.length())
{
cur->next->next = head;
head-> pred = cur-> next->pred;
}
}
}
}
void print() const
{
Node *cur = head->next;
while( cur != head)
{
cout << cur-> value;
cur = cur-> next;
}
}
};
#endif
You don't seem to understand constructors very well.
Only one constructor is called when you initialize your class. You can call a constructor from another constructor if you want, but that's not by defaut: Can I call a constructor from another constructor (do constructor chaining) in C++?.
In your instance, your second constructor should probably be something like this: MyList(const string& str): MyList() { ... }
That way head wil be properly initalized, and you won't create a segfault.
Additionnally you could run your code in debug mode, in the debugger, and find out the line your code crashes. using namespace ...; in a header is also a bad practice, as you don't know where your header will be included.
It's hard to say exactly what's happening without see how you're using these classes but your MyList constructor overloaded on string is broken right off the bat. It sets count to 0 so you know it will always enter the if clause and never the else.
MyList(const string& str): count(0)
{
Node *cur = head;
if(count == 0)
{
head-> pred = head;
head-> next = head;
}
else . . .
inside the if statement, it tries to dereference head which has never been assigned a value. You do set it in the default constructor but that one also doesn't seem to do anything else.
The purpose of a constructor is to construct a valid object from scratch. Sometimes one constructor overload might delegate to another to avoid repeated code but I'm not sure what you're trying to do here.
Assuming the second constructor was meant to actually be a helper method, well it still doesn't work because count never goes above zero (except in the else clause but you can't get there with count==0).
I'll admit I didn't look very carefully but I'm guessing that if execution this far:
cur->next->next
is not always going to be set when you try to access it. if cur->next is nullptr then your program dies.
I'm having problems with the following situation. I have three classes that are involved in this mixup. List, ListNode, City. I have a List<City *>, where the list will be made up of a set of ListNode<City *> (standard wrapper around the list nodes).
City is an abstract class, so there are several classes that inherit from it that could be placed in this list and accessed polymorphically. The List class has a getHead() method which returns a pointer to a ListNode that is the head.
Any city has a population, so to access the populations, I'd expect the following to work. It's not, thus my question. I broke it down into pieces to make it simpler along the way:
ListNode<City *> *head= country->city_list->getHead();
City *headnode = *head->getNode();
cout << "Test: " << headnode->getPopulation() << endl;
getPopulation() returns an integer. country is defined as List<City*> *city; Any help on how I could figure out my problem would be greatly appreciated.
edit adding more code for better idea of what I'm working with. First, ListNode:
template <class T>
class ListNode
{
public:
ListNode() {next = 0;node = 0;};
ListNode(T *t) {node = t; next = 0;};
ListNode(const ListNode &l)
{
//long copy constructor. snip.
};
T *getNode() const { return node; }
ListNode *getNext() const { return next; };
private:
T *node;
ListNode *next;
};
Now, here is what might relevant in the List class..
template <class T>
class List
{
public:
List()
{
head = 0;
size = 0;
};
List(ListNode<T> *t)
{
head = t;
size = 1;
};
List(T *t)
{
head = new ListNode<T>(t);
size = 1;
};
List(const List<T> &t)
{
// long copy constructor. snip.
};
//bunch of irrelevent methods.
ListNode<T> *getHead() const {return head;};
List &operator+=(T &t)
{
this->insert(&t);
size++;
return (*this);
};
private:
List &insert(T *t)
{
ListNode<T> *current = head;
if (current == 0)
{
head = new ListNode<T>(t);
}
else
{
while (current->getNext() != 0)
{
current = current->getNext();
}
current->setNext(new ListNode<T>(t));
}
return (*this);
};
ListNode<T> *head;
int size;
};
I have a hunch that the process of inserting might be the problem. I insert with the List class's += operator, shown in the List implementation above. It calls the private insert method shown above, as well. It looks like this:
City *somecity = new City(x,y,z); //some parameters. integers.
*city_list += somecity; // where city_list is a List.
I think you've got a variable scoping problem.
Your ListNode class contains a pointer to the node value. Your ListNode constructor takes in a pointer to the node value and saves it.
The problem is if that pointer is to a local variable that then goes out of scope. Your ListNode's node pointer is now pointing to an object that doesn't exist. e.g. in this example
addToList(List<int>& myList)
{
int x = 3;
myList += x; // pointer to x is in the list
}
// Out of scope; x no longer exists, but myList has a pointer to it.
// Accessing this node will result in an error.
There are a couple possible remedies:
Have your ListNode contain values rather than pointers. The drawback here is that you will be making copies of the values
Implement ListNode using a reference counted smart pointer which will manager the lifetime of the object.
Well, what you could do is:
ListNode<City *>* head = new ListNode<City*>(country->city_list->getHead());
City* headnode = head->getNode();
cout << "Test: " << headnode->getPopulation() << endl;
It will take the existing City (on the memory) and put it at the head of the List node, and so on.
and if you want to copy them, maybe you could just make this:
ListNode<City *>* head = new ListNode<City*>*(new City(country->city_list->getHead()));
City* headnode = new City(head->getNode());
cout << "Test: " << headnode->getPopulation() << endl;
Hope it will help you.
I would like to ask you how to write a copy constructor (and operator = ) for the following classes.
Class Node stores coordinates x,y of each node and pointer to another node.
class Node
{
private:
double x, y;
Node *n;
public:
Node (double xx, double yy, Node *nn) : x(xx), y(yy), n(nn) {}
void setNode (Node *nn) : n(nn) {}
...
};
Class NodesList (inherited from std:: vector) stores all dynamically allocated Nodes
class NodesList : public std::vector<Node *>
{}
The main program:
int main()
{
Node *n1 = new Node(5,10,NULL);
Node *n2 = new Node(10,10,NULL);
Node *n3 = new Node(20,10,NULL);
n1->setNode(n2);
n2->setNode(n3);
n3->setNode(n2);
NodesList nl1;
nl1.push_back(n1);
nl1.push_back(n2);
nl1.push_back(n3);
//Copy contructor is used, how to write
NodesList nl2(nl1);
//OPerator = is used, how to write?
NodesList nl3 = nl1;
}
I do not want to create a shallow copy of each node but a deep copy of each node. Could I ask you for a sample code with copy constructor?
Each node can be pointed more than once. Let us have such situation, when 3 nodes n[1], n[2], n[3] are stored in the NodesList nl1:
n[1] points to n[2]
n[2] points to n[3]
n[3] points to n[2]
A] Our copy constructor process the node n[1]. It creates a new object n[1]_new represented by the copy of the old object n[1]_old. The node n[2] pointed from n[1]_old still does not exist, so n[2]_new must be also created... The pointer from n1_new to n2_new is set.
B] Then second point n[2] is processed. It can not be created twice, n[2]_new was created in A]. But pointed node n[3] does not exist, so the new object n[3]_new as a copy of an old object n[3]_old is created. The pointer from n2_new to n3_new is set.
C] Node n[3]_new has already been created and n[2]_new. The pointer from n3_new to n2_new is set and no other object will be created...
So the copy constructor should check whether the object has been created in the past or has not...
Some reference counting could be helpful...
There is my solution of the problem. A new data member n_ref storing a new verion of the node n was added:
class Node
{
private:
double x, y;
Node *n, *n_ref;
public:
Node (double xx, double yy, Node *nn) : x(xx), y(yy), n(nn) {n_ref = NULL;}
Node * getNode() {return n;}
Node * getRefNode () {return n_ref;}
void setNode (Node *nn) {this->n = nn;}
void setRefNode (Node *nn) {this->n_ref = nn;}
The copy constructor creates a shallow copy of the node:
Node (const Node *node)
{
x = node->x;
y = node->y;
n = node->n;
n_ref = node->n_ref;
}
The copy constructor for NodesList
NodesList::NodesList(const NodesList& source)
{
const_iterator e = source.end();
for (const_iterator i = source.begin(); i != e; ++i) {
//Node* n = new Node(**i);
//Node n still has not been added to the list
if ((*i)->getRefNode() == NULL)
{
//Create node
Node *node = new Node(*i);
//Add node to the list
push_back(node);
//Set this note as processed
(*i)->setRefNode(node);
//Pointed node still has not been added to the list
if ((*i)->getNode()->getRefNode() == NULL)
{
//Create new pointed node
Node *node_pointed = new Node ((*i)->getNode());
//Add node to the list
push_back(node_pointed);
//Set pointer to n
node->setNode(node_pointed);
//Set node as processed
((*i)->getNode())->setRefNode(node_pointed);
}
//Pointed node has already been added to the list
else
{
//Set pointer to node n
node->setNode((*i)->getRefNode());
}
}
//Node n has already been added to the list
else
{
//Get node
Node * node = (*i)->getRefNode();
//Pointed node still has not been added
if ((*i)->getNode()->getRefNode() == NULL)
{
//Create new node
Node *node_pointed = new Node ((*i)->getNode());
//Add node to the list
push_back(node_pointed);
//Set pointer to n
node->setNode(node_pointed);
//Set node as processed
((*i)->getNode())->setRefNode(node_pointed);
}
//Pointed node has already been added to the list
else
{
//Set pointer to n
node->setNode((*i)->getNode()->getRefNode());
}
}
}
}
Perform a shallow copy in NodeList::NodeList(const NodeList&) and you don't have to worry about cycles breaking the copy operation. Disclaimer: the following is untested, incomplete and may have bugs.
class NodeList {
private:
typedef std::vector<Node*> Delegate;
Delegate nodes;
public:
NodeList(int capacity=16) : nodes() { nodes.reserve(capacity); }
NodeList(const NodeList& from);
virtual ~NodeList();
NodeList& operator=(const NodeList& from);
/* delegated stuff */
typedef Delegate::size_type size_type;
typedef Delegate::reference reference;
typedef Delegate::const_reference const_reference;
typedef Delegate::iterator iterator;
typedef Delegate::const_iterator const_iterator;
size_type size() const { return nodes.size(); }
iterator begin() { return nodes.begin(); }
const_iterator begin() const { return nodes.begin(); }
iterator end() { return nodes.end(); }
const_iterator end() const { return nodes.end(); }
// ...
};
NodeList::NodeList(const NodeList& from)
: nodes(from.size()), flags(NodeList::owner)
{
std::map<Node*, Node*> replacement;
Delegate::const_iterator pfrom;
Delegate::iterator pto;
// shallow copy nodes
for (pfrom=from.begin(), pto=nodes.begin();
pfrom != from.end();
++pfrom, ++pto)
{
replacement[*pfrom] = *pto = new Node(**pfrom);
}
// then fix nodes' nodes
for (pto = nodes.begin(); pto != nodes.end(); ++pto) {
(*pto)->setNode(replacement[(*pto)->getNode()]);
}
}
NodeList::operator=(const NodeList&) can use the copy-swap idiom, the same as Tronic's Node::operator=(const Node&).
This design has a potential memory leak in that a copied NodeList is (initally) the only place that references its nodes. If a temporary NodeList goes out of scope, a poor implementation will leak the Nodes the list contained.
One solution is to proclaim that NodeLists own Nodes. As long as you don't add a Node to more than one NodeList (via NodeList::push_back, NodeList::operator[] &c), NodeList's methods can delete nodes when necessary (e.g. in NodeList::~NodeList, NodeList::pop_back).
NodeList::~NodeList() {
Delegate::iterator pnode;
for (pnode = nodes.begin(); pnode != nodes.end(); ++pnode) {
delete *pnode;
}
}
void NodeList::pop_back() {
delete nodes.back();
nodes.pop_back();
}
Another solution is to use smart pointers, rather than Node*. NodeList should store shared pointers. Node::n should be a weak pointer to prevent ownership cycles.
I would just use std::list<Node> instead of NodesList. Well, let's code...
NodesList::NodesList(const NodesList& source)
{
const_iterator e = source.end();
for (const_iterator i = source.begin(); i != e; ++i) {
Node* n = new Node(**i);
push_back(n);
}
}
Apparently each Node is only allowed to point to another Node in the same list? Otherwise the "deep copy" of a list needs more definition. Should it not be connected to the original NodeList? Should it not be connected to any original Node? Are copies of Nodes not in the list being copied added to some other list or free-floating?
If all the Node-to-Node pointers are constrained within the NodeList, then perhaps you should store indexes instead of pointers, then no special handling is required.
You should not inherit from standard library containers (because they lack virtual destructors). Instead, include them as member variables in your classes.
Since you want a deep copy, you need these: (rule of three)
Node(Node const& orig): x(orig.x), y(orig.y), n() {
if (orig.n) n = new Node(*orig.n);
}
Node& operator=(Node const& orig) {
// The copy-swap idiom
Node tmp = orig;
swap(tmp); // Implementing this member function left as an exercise
return *this;
}
~Node() { delete n; }
A better idea might be to avoid using pointers entirely and just put your nodes in a suitable container.