I have a base class Node for a generic tree:
class Node {
public:
Node() {
parent = NULL;
name = "";
rule = NULLRULE;
childs = std::vector<Node*>();
};
void addChild(Node* child){
childs.push_back(child);
child->setParent(this);
};
void setParent(Node* p) {
this->parent = p;
}
virtual ~Node(){
if (childs.size() == 0) return;
// remove duplicate childs
// since we allow having same child.
std::sort(childs.begin(), childs.end());
childs.erase(std::unique(childs.begin(), childs.end()), childs.end());
for(unsigned int i = 0; i < childs.size(); i++) {
delete childs[i];
}
}
And I have derived class NodeSquare, NodeCircle etc... All the node formed a tree in the following class:
class Tree {
Tree() {};
~Tree() {
delete root;
};
void BFS(){};
etc...
Node* root;
}
How do I define a copy constructor for the Tree class? I am passing the tree through reference, that's why I need a copy constructor ...
processTree(Tree& t) {
t = Tree();
}
Tree(const Tree & copy)
{
if(copy != *this)
{
//to do
}
}
A copy constructif hais this signature , then if the scope you assign your data like a normal constructor the statement is for safety but you can use à list initializer.
Related
I am writing an Ordered Linked List class definition (OLList). I have written the assignment operator function, but when I try to test it by chaining assignment operations, the program gets caught in the while loop of the OLList::copy function. I know this because I tested using console prints.
//OLList.h
struct Node {
ListItem item;
Node *next;
};
class OLList {
public:
OLList& OLList::operator =(const OLList& rhs)
{
if (this != &rhs) {
destroy();
copy(rhs);
}
return *this;
}
void OLList::destroy()
{
Node *current_node = this->headM;
Node *next_node;
while(current_node->next != nullptr)
{
next_node = current_node->next;
delete(current_node);
current_node = next_node;
}
return;
}
void OLList::copy(const OLList& source)
{
Node *new_node, *current_node;
Node *current_source_node = source.headM;
this->headM->item = source.headM->item;
current_node = this->headM;
while(current_source_node->next != nullptr)
{
new_node = new(Node);
current_node->next = new_node;
current_node = current_node->next;
current_source_node = current_source_node->next;
current_node->item = current_source_node->item;
}
return;
}
}
Below is the code used to test the class. I have made sure that the print() function works fine so that's definitely not an issue.
//main.cpp
int main()
{
OLList the_list;
the_list.insert(1);
the_list.insert(2);
OLList second_list;
second_list.insert(3);
second_list.insert(4);
OLList third_list;
third_list.insert(5);
third_list.insert(6);
third_list = second_list = the_list;
third_list.print();
}
When it is compiled and run, the program never terminates as it is caught in the loop mentioned above.
Your destroy() method will fail if headM is nullptr. You should be using while(current_node != nullptr) instead of while(current_node->next != nullptr). But more importantly, it doesn't reset headM to nullptr after destroying the list. So after operator= calls destroy(), headM is no longer in a valid state for copy() to use.
Your copy() method is similarly not checking if either source or target headM are nullptr. But more importantly, it assumes the target list is empty beforehand, otherwise it leaks memory, if it does not crash outright (per above). And frankly, it simply is not coded correctly in general to copy one list to another.
So, your code is invoking undefined behavior, this anything could happen.
Like #PaulMcKenzie stated in comments, you really should be using a proper copy constructor instead (and a destructor - and since you are clearly using C++11 or later, a move constructor and move assignment operator, too - see the Rule of 5). Your assignment operator can then be implemented using your copy constructor (and likewise for move assignment).
Try something more like this:
struct Node {
ListItem item;
Node *next = nullptr;
Node(const ListItem &value) : item(value) {}
};
class OLList {
private:
Node *headM = nullptr;
public:
OLList() = default;
OLList(const OLList &src)
{
Node *current_source_node = src.headM;
Node **current_node = &headM;
while (current_source_node)
{
*current_node = new Node(current_source_node->item);
current_node = &((*current_node)->next);
current_source_node = current_source_node->next;
}
/* alternatively:
Node *current_source_node = src.headM;
while (current_source_node) {
insert(current_source_node->item);
}
*/
}
OLList(OLList&& src)
{
src.swap(*this);
}
~OLList()
{
Node *next_node;
while (headM)
{
next_node = headM->next;
delete headM;
headM = next_node;
}
}
void clear() {
OLList().swap(*this);
}
OLList& operator=(const OLList& rhs)
{
if (this != &rhs) {
OLList(rhs).swap(*this);
}
return *this;
}
OLList& OLList::operator=(OLList&& rhs)
{
OLList(std::move(rhs)).swap(*this);
return *this;
}
void swap(OLList &other) {
std::swap(headM, other.headM);
}
void insert(const ListItem &value) {
...
}
void print() const {
...
}
...
};
First, sorry for the long code. I did my best to trim it as small as possible.
I'm getting segmentation fault when i want to add a new element (void SLList::pushBack(const Data &rDATA)) to my singly linked list (in SLList.hxx). The segmentation fault caused by 0xbaadf00d value.
........................................................................................................
IniFile.h
#include "Section.h"
class IniFile
{
public:
IniFile() :
void addSection();
private:
SLList<Section> mContent;
};
IniFile.cpp
#include "IniFile.h"
IniFile::IniFile() :
mContent() {}
void IniFile::addSection() // This is the only one method what i call
{
mContent.pushBack(Section());
}
Section.h
#include "Pair.hxx"
#include "SLList.hxx"
class Section
{
public:
Section();
private:
SLList<Pair<std::string, std::string>> mKeyValuePairs;
};
Section.cpp
#include "Section.h"
Section::Section() :
mKeyValuePairs() {}
SLList.hxx
template <typename Data>
class SLList
{
public:
class Node
{
public:
Node(const Data &rDATA, Node *const pNEXT = nullptr) :
mData(rDATA),
mNext(pNEXT) {}
Node(const Node &rRHS)
{
mData = rRHS.mData;
*mNext = *rRHS.mNext;
}
~Node()
{
delete mNext;
}
Node &operator=(const Node &rRHS)
{
if (&rRHS == this)
return *this;
mData = rRHS.mData;
*mNext = *rRHS.mNext;
return *this;
}
private:
void setNext(Node *const pNext)
{
mNext = pNext;
}
friend void SLList<Data>::pushBack(const Data &rDATA);
private:
Data mData;
Node *mNext;
};
SLList() :
mHead(nullptr),
mTail(nullptr) {}
SLList(const SLList &rRHS)
{
*mHead = *rRHS.mHead;
*mTail = *rRHS.mTail;
}
SLList &operator=(const SLList &rRHS)
{
if (&rRHS == this)
return *this;
*mHead = *rRHS.mHead;
*mTail = *rRHS.mTail;
return *this;
}
~SLList()
{
clear();
}
void clear()
{
delete mHead;
}
void pushBack(const Data &rDATA)
{
Node *pNode = new Node(rDATA, nullptr); // I get segmentation fault at this point
if (!mTail)
{
mHead = pNode;
mTail = pNode;
}
else
{
mTail->setNext(pNode);
mTail = pNode;
}
}
private:
Node *mHead;
Node *mTail;
};
Pair.hxx
template <typename T1, typename T2>
class Pair
{
public:
Pair(const T1 &rFIRST, const T2 &rSECOND) :
mFirst(rFIRST),
mSecond(rSECOND) {}
private:
T1 mFirst;
T2 mSecond;
};
SLList's copy constructor and assignment operator are wrong in terms of Node* pointer management.
Also, Node's destructor shouldn't destroy the next Node object in the list. Not only is a recursive destructor bad for long lists, but also think of in the future if you ever want to remove a single Node without clearing the whole list. Your clear() method should directly iterate the list deleting Node objects one at a time without using recursion.
Try something more like this:
#include <utility>
template <typename Data>
class SLList
{
public:
class Node
{
public:
Node(const Data &rDATA, Node *const pNEXT = nullptr)
: mData(rDATA), mNext(pNEXT)
{
}
Node(const Node &rSRC)
: mData(rSRC.mData), mNext(nullptr)
{
}
Node &operator=(const Node &rRHS)
{
if (&rRHS != this)
mData = rRHS.mData;
return *this;
}
private:
Data mData;
Node *mNext;
friend class SLList<Data>;
};
SLList()
: mHead(nullptr), mTail(nullptr)
{
}
SLList(const SLList &rSRC)
: mHead(nullptr), mTail(nullptr)
{
Node *pNode = rSRC.mHead;
while (pNode)
{
pushBack(pNode->mData);
pNode = pNode->mNext;
}
}
SLList &operator=(const SLList &rRHS)
{
if (&rRHS != this)
{
SLList temp(rRHS);
std::swap(mHead, temp.mHead);
std::swap(mTail, temp.mTail);
}
return *this;
}
~SLList()
{
clear();
}
void clear()
{
Node *pNode = mHead;
mHead = mTail = nullptr;
while (pNode)
{
Node *pNext = pNode->mNext;
delete pNode;
pNode = pNext;
}
}
void pushBack(const Data &rDATA)
{
Node *pNode = new Node(rDATA);
if (!mHead) mHead = pNode;
if (mTail) mTail->mNext = pNode;
mTail = pNode;
}
private:
Node *mHead;
Node *mTail;
};
With that said, what you really should do is use std::list (or std::forward_list) and std::pair instead. There is no benefit to "reinventing the wheel" at all:
#include "Section.h"
#include <list>
class IniFile
{
public:
void addSection();
private:
std::list<Section> mContent;
};
#include "IniFile.h"
void IniFile::addSection()
{
mContent.push_back(Section());
}
#include <pair>
#include <list>
#include <string>
class Section
{
private:
std::list<std::pair<std::string, std::string>> mKeyValuePairs;
};
#include <list>
template <typename Data>
class SLList
{
public:
void clear()
{
mList.clear();
}
void pushBack(const Data &rDATA)
{
mList.push_back(rDATA);
}
private:
std::list<Data> mList;
};
I was working for writing a copy constructor for List class with requirement as not to use any other methods in implementation.
The class fragment is as follows :
class List {
private:
struct Node {
NodeData *data;
Node *next;
};
Node *head;
};
The requirement is to write copy constructor for this class and do not use any other methods in implementation except that we may use copy constructor for NodeData class
I have written the copy constructor as follows:
list::list(const list &t){
Node* q;
q=new Node;
while (p!=NULL){
q->x= p->x;}
}
This is not working, please help in how to write the copy constructor as required.
I disagree with the commentors that this is a moronic exercise, actually its interesting to try and do this. The following should give you an idea on what to try: http://ideone.com/DdC7bN
class List {
private:
struct Node {
int data; // simplification
Node *next;
Node(int d) {
data = d;
next = NULL;
}
};
protected:
Node *head;
Node *tail;
public:
List(int d) : head(new Node(d)), tail(head) {}
void append(int d) {
Node* n = new Node(d);
tail->next = n;
tail = n;
}
List(const List& rhs) {
if (head) delete head;
head=new Node(rhs.head->data);
Node* lhsCurrent = head;
Node* rhsCurrent = rhs.head->next;
do {
lhsCurrent->next = new Node(rhsCurrent->data);
rhsCurrent = rhsCurrent->next;
lhsCurrent = lhsCurrent->next;
} while (rhsCurrent!=NULL);
tail = lhsCurrent;
}
};
int main() {
List first(5);
first.append(6);
List second(first);
return 0;
}
This question already has answers here:
What is object slicing?
(18 answers)
Closed 8 years ago.
I have two classes, Object and Ball. Ball is derived from Object. Object has a virtual function "move" and a non virtual function "moveFast" that calls move. Class Ball redefines the move function from it's parent class.
#include <iostream>
struct Object
{
virtual void move(int dist)
{
std::cout<<"Moving "<<dist<<std::endl;
}
void moveFast(int multiplier)
{
move(10*multiplier);
}
};
struct Ball : public Object
{
void move(int dist)
{
std::cout<<"Rolling "<<dist<<std::endl;
}
};
class List
{
struct Node
{
Node* next;
Object ele;
Node(Object e, Node* n=NULL) : ele(e), next(n){}
};
Node* head;
public:
List() : head(NULL){}
void addObj(Object o)
{
if(head==NULL)
{
head = new Node(o);
return;
}
Node* current = head;
while(current->next!=NULL)
{
current=current->next;
}
Node* obj = new Node(o);
current->next=obj;
}
void doStuff()
{
Node* current = head;
while(current!= NULL)
{
current->ele.moveFast(10);
current=current->next;
}
}
};
int main()
{
Object a,b,c;
Ball d;
List list;
list.addObj(a);
list.addObj(b);
list.addObj(c);
list.addObj(d);
list.doStuff();
}
The List class takes in Objects and calls their moveFast function. Because a,b, and c are just Objects I would expect the first 3 lines of output to be "Moving 100".
d however, is an instance of the Ball class. So I would expect the 4th line of output to say "Rolling 100", because Ball redefined the move function.
Right now all the output prints
Moving 100
Moving 100
Moving 100
Moving 100
Is there a way to get Ball's definition of move called from List?
The problem is that you store your Objects in the list by value. virtual functions will only work on pointers. the moment you try to add an object to the list through list::void addObj(Object o). The argument is passed by value. This means that it is copied and if you copy a base class only the base class functionality will be copied it's called the slicing problem (like dyp mentioned). you should change your nodes to hold a pointer to the object and redo your add object function to take a pointer to the element to prevent copying and slicing.
like this
class List
{
struct Node
{
Node* next;
Object* ele;
Node(Object* e, Node* n=nullptr) : ele(e), next(n){}
};
Node* head;
public:
List() : head(nullptr){}
void addObj(Object* o)
{
if(head==nullptr)
{
head = new Node(o);
return;
}
Node* current = head;
while(current->next!=nullptr)
{
current=current->next;
}
Node* obj = new Node(o);
current->next=obj;
}
void doStuff()
{
Node* current = head;
while(current!= nullptr)
{
current->ele->moveFast(10);
current=current->next;
}
}
};
int main()
{
Object a,b,c;
Ball d;
List list;
list.addObj(&a);
list.addObj(&b);
list.addObj(&c);
list.addObj(&d);
list.doStuff();
return 0;
}
which outputs:
Moving 100
Moving 100
Moving 100
Rolling 100
Like many have said, there was a slicing problem in List.
List::Node stored an actual Object, so when an instance of Ball was passed into addObj(Object o), the additional functionality of Ball was "sliced", and only the parts stored by it's base class "Object" remained.
Changing the Node class to store an Object pointer instead of an Object instance fixed this problem. This change also requires the addObj function to be altered to take in a pointer. The List class now looks like this:
class List
{
struct Node
{
Node* next;
Object* ele;//<-- This is the Big change
Node(Object* e, Node* n=NULL) : ele(e), next(n){}
};
Node* head;
public:
List() : head(NULL){}
void addObj(Object* o)
{
if(head==NULL)
{
head = new Node(o);
return;
}
Node* current = head;
while(current->next!=NULL)
{
current=current->next;
}
Node* obj = new Node(o);
current->next=obj;
}
void doStuff()
{
Node* current = head;
while(current!= NULL)
{
current->ele->moveFast(10);
current=current->next;
}
}
};
changing int main() to provide the altered inputs results in the expected output.
int main()
{
Object *a,*b,*c;
b=c=a=new Object();
Ball* d = new Ball();
List list;
list.addObj(a);
list.addObj(b);
list.addObj(c);
list.addObj(d);
list.doStuff();
}
I have a Tree class with the following definition:
class Tree {
Tree();
private:
TreeNode *rootPtr;
}
TreeNode represents a node and has data, leftPtr and rightPtr.
How do I create a copy of a tree object using a copy constructor? I want to do something like:
Tree obj1;
//insert nodes
Tree obj2(obj1); //without modifying obj1.
Any help is appreciated!
Pseudo-code:
struct Tree {
Tree(Tree const& other) {
for (each in other) {
insert(each);
}
}
void insert(T item);
};
Concrete example (changing how you walk the tree is important to know, but detracts from showing how the copy ctor works, and might be doing too much of someone's homework here):
#include <algorithm>
#include <iostream>
#include <vector>
template<class Type>
struct TreeNode {
Type data;
TreeNode* left;
TreeNode* right;
explicit
TreeNode(Type const& value=Type()) : data(value), left(0), right(0) {}
};
template<class Type>
struct Tree {
typedef TreeNode<Type> Node;
Tree() : root(0) {}
Tree(Tree const& other) : root(0) {
std::vector<Node const*> remaining;
Node const* cur = other.root;
while (cur) {
insert(cur->data);
if (cur->right) {
remaining.push_back(cur->right);
}
if (cur->left) {
cur = cur->left;
}
else if (remaining.empty()) {
break;
}
else {
cur = remaining.back();
remaining.pop_back();
}
}
}
~Tree() {
std::vector<Node*> remaining;
Node* cur = root;
while (cur) {
Node* left = cur->left;
if (cur->right) {
remaining.push_back(cur->right);
}
delete cur;
if (left) {
cur = left;
}
else if (remaining.empty()) {
break;
}
else {
cur = remaining.back();
remaining.pop_back();
}
}
}
void insert(Type const& value) {
// sub-optimal insert
Node* new_root = new Node(value);
new_root->left = root;
root = new_root;
}
// easier to include simple op= than either disallow it
// or be wrong by using the compiler-supplied one
void swap(Tree& other) { std::swap(root, other.root); }
Tree& operator=(Tree copy) { swap(copy); return *this; }
friend
ostream& operator<<(ostream& s, Tree const& t) {
std::vector<Node const*> remaining;
Node const* cur = t.root;
while (cur) {
s << cur->data << ' ';
if (cur->right) {
remaining.push_back(cur->right);
}
if (cur->left) {
cur = cur->left;
}
else if (remaining.empty()) {
break;
}
else {
cur = remaining.back();
remaining.pop_back();
}
}
return s;
}
private:
Node* root;
};
int main() {
using namespace std;
Tree<int> a;
a.insert(5);
a.insert(28);
a.insert(3);
a.insert(42);
cout << a << '\n';
Tree<int> b (a);
cout << b << '\n';
return 0;
}
It depends on whether you want a shallow or deep copy. Assuming a deep copy, you need to be able to copy whatever's at the "leaves" hanging off a TreeNode object; so ideally the functionality should be in TreeNode (unless Tree is a friend class of TreeNode that you've designed to be deeply familiar with its implementation, which is often the case of course;-). Assuming something like...:
template <class Leaf>
class TreeNode {
private:
bool isLeaf;
Leaf* leafValue;
TreeNode *leftPtr, *rightPtr;
TreeNode(const&Leaf leafValue);
TreeNode(const TreeNode *left, const TreeNode *right);
...
then you could add to it a
public:
TreeNode<Leaf>* clone() const {
if (isLeaf) return new TreeNode<Leaf>(*leafValue);
return new TreeNode<Leaf>(
leftPtr? leftPtr->clone() : NULL,
rightPtr? rightPtr->clone() : NULL,
);
}
If Tree is taking care of this level of functionality (as a friend class), then obviously you'll have the exact equivalent but with the node being cloned as an explicit arg.
Two basic options:
If you have an iterator available, you can simply iterate over the elements in the tree and insert each one manually, as R. Pate described. If your tree class doesn't take explicit measures to balance the tree (e.g. AVL or red-black rotations), you'll end up effectively with a linked list of nodes this way (that is, all the left child pointers will be null). If you are balancing your tree, you'll effectively do the balancing work twice (since you already had to figure it out on the source tree from which you're copying).
A quicker but messier and more error-prone solution would be to build the copy top down by doing a breadth-first or depth-first traversal of the source tree structure. You wouldn't need any balancing rotations and you'd end up with an identical node topology.
Here's another example I used with a binary tree.
In this example, node and tree are defined in separate classes and a copyHelper recursive function helps the copyTree function. The code isn't complete, I tried to put only what was necessary to understand how the functions are implemented.
copyHelper:
void copyHelper( BinTreeNode<T>* copy, BinTreeNode<T>* originalNode ) {
if (originalTree == NULL)
copy = NULL;
else {
// set value of copy to that of originalTree
copy->setValue( originalTree->getValue() );
if ( originalTree->hasLeft() ) {
// call the copyHelper function on a newly created left child and set the pointers
// accordingly, I did this using an 'addLeftChild( node, value )' function, which creates
// a new node in memory, sets the left, right child, and returns that node. Notice
// I call the addLeftChild function within the recursive call to copyHelper.
copyHelper(addLeftChild( copy, originalTree->getValue()), originalTree->getLeftChild());
}
if ( originalTree->hasRight() ) { // same with left child
copyHelper(addRightChild(copy, originalTree->getValue()), originalTree->getRightChild());
}
} // end else
} // end copyHelper
copy: returns a pointer to the new tree
Tree* copy( Tree* old ) {
Tree* tree = new Tree();
copyHelper( tree->root, oldTree->getRoot() );
// we just created a newly allocated tree copy of oldTree!
return tree;
} // end copy
Usage:
Tree obj2 = obj2->copy(obj1);
I hope this helps someone.
When your class has a pointer pointing to dynamically allocated memory, in the copy constructor of that class you need to allocate memory for newly created object. Then you need to initialize newly allocated memory with whatever the other pointer pointing at. Here is an example how you need to deal with a class having dynamically allocated memory:
class A
{
int *a;
public:
A(): a(new int) {*a = 0;}
A(const A& obj): a(new int)
{
*a = *(obj.a);
}
~A() {delete a;}
int get() const {return *a;}
void set(int x) {*a = x;}
};
You can try something like (untested)
class Tree {
TreeNode *rootPtr;
TreeNode* makeTree(Treenode*);
TreeNode* newNode(TreeNode* p)
{
TreeNode* node = new Treenode ;
node->data = p->data ;
node->left = 0 ;
node->right = 0 ;
}
public:
Tree(){}
Tree(const Tree& other)
{
rootPtr = makeTree(other.rootPtr) ;
}
~Tree(){//delete nodes}
};
TreeNode* Tree::makeTree(Treenode *p)
{
if( !p )
{
TreeNode* pBase = newNode(p); //create a new node with same data as p
pBase->left = makeTree(p->left->data);
pBase->right = makeTree(p->right->data);
return pBase ;
}
return 0 ;
}