270 likes | 401 Views
Dynamic Data, Shallow Copies, and Deep Copies. Problem. Consider the following program that creates a grade tree makes a copy of the tree to save modifies the original tree. #include “stutree.h” int main() { Gradetree mygrades; // list of my grades
E N D
Problem • Consider the following program that • creates a grade tree • makes a copy of the tree to save • modifies the original tree
#include “stutree.h” int main() { Gradetree mygrades; // list of my grades mygrades.Insert(90); // put some grades in my list mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; // save a copy of my grades at this point in term savemygrades = mygrades; mygrades.Insert(99); // add/delete more grades mygrades.Delete(86); }
NULL #include “stutree.h” int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; savemygrades = mygrades; mygrades.Insert(99); mygrades.Delete(86); } mygrades.root
90 #include “stutree.h” int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; savemygrades = mygrades; mygrades.Insert(99); mygrades.Delete(86); } mygrades.root
90 #include “stutree.h” int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; savemygrades = mygrades; mygrades.Insert(99); mygrades.Delete(86); } mygrades.root 86
90 #include “stutree.h” int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; savemygrades = mygrades; mygrades.Insert(99); mygrades.Delete(86); } mygrades.root 86 97
90 #include “stutree.h” int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; savemygrades = mygrades; mygrades.Insert(99); mygrades.Delete(86); } mygrades.root 86 97 NULL savemygrades.root
90 #include “stutree.h” int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; savemygrades = mygrades; mygrades.Insert(99); mygrades.Delete(86); } mygrades.root 86 97 savemygrades.root
90 #include “stutree.h” int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; savemygrades = mygrades; mygrades.Insert(99); mygrades.Delete(86); } mygrades.root 86 97 This is called a shallow copy Only the private data is copied to the new class instance There is really only one copy of the dynamic data! savemygrades.root
90 #include “stutree.h” int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; savemygrades = mygrades; mygrades.Insert(99); mygrades.Delete(86); } mygrades.root 86 97 99 savemygrades.root
90 #include “stutree.h” int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; savemygrades = mygrades; mygrades.Insert(99); mygrades.Delete(86); } mygrades.root 97 99 savemygrades.root
90 #include “stutree.h” int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); Gradetree savemygrades; savemygrades = mygrades; mygrades.Insert(99); mygrades.Delete(86); } mygrades.root 97 99 savemygrades.root Problem: I really didn’t get two copies of my grades, so when I make changes to mygrades, I really am changing both mygrades and savemygrades!
Problem • Consider the following program that • creates a grade tree • calls a function, passing the grade tree by value • modifies the copy of the tree passed to the function • returns to the main function
#include “stutree.h” void GradeFunction (Gradetree tempgrades) { tempgrades.Insert(99); tempgrades.Delete(86); } int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); GradeFunction(mygrades); } 90 mygrades.root 86 97
#include “stutree.h” Void GradeFunction (Gradetree tempgrades) { tempgrades.Insert(99); tempgrades.Delete(86); } int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); GradeFunction(mygrades); } tempgrades.root 90 mygrades.root 86 97
#include “stutree.h” Void GradeFunction (Gradetree tempgrades) { tempgrades.Insert(99); tempgrades.Delete(86); } int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); GradeFunction(mygrades); } tempgrades.root 90 mygrades.root 86 97 99
#include “stutree.h” Void GradeFunction (Gradetree tempgrades) { tempgrades.Insert(99); tempgrades.Delete(86); } int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); GradeFunction(mygrades); } tempgrades.root 90 mygrades.root 97 99
Problem: Passing a class by value only gives a shallow copy, so function actually modifies mygrades! #include “stutree.h” Void GradeFunction (Gradetree tempgrades) { tempgrades.Insert(99); tempgrades.Delete(86); } int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); GradeFunction(mygrades); } tempgrades.root 90 mygrades.root 97 99
#include “stutree.h” Void GradeFunction (Gradetree tempgrades) { tempgrades.Insert(99); tempgrades.Delete(86); } int main() { Gradetree mygrades; mygrades.Insert(90); mygrades.Insert(86); mygrades.Insert(97); GradeFunction(mygrades); // execution continues here after function call } 90 mygrades.root 97 99
Solution • We need deep copies in the two previous situations • A deep copy is a copy of not only the private root pointer, but also a copy of all of the dynamic data, i.e., a copy of all nodes in the entire tree • Can you think of other classes we have used that needed deep copies? • any class using linked lists (files gradelnklist, stackll, queuell)
Solution (continued) • Add a function to the Gradetree class that makes a deep copy when the assignment operator is used • This is a function that overloads the assignment operator, i.e., the = sign. • I actually already included this function in the Gradetree class
Solution (continued) • Add a function to the Gradetree class that makes a deep copy when the class is passed by value to a function • This is a function called a copy constructor. • The copy constructor is called when a class is passed by value. • I actually already included this function in the Gradetree class
stutree.h class Gradetree { public: // default constructor Gradetree (); // copy constructor - for deep copies Gradetree (const Gradetree& othergradetree); // destructor ~Gradetree (); // overload assignment for deep copies void operator= (const Gradetree& othergradetree); . . . private: Treenode* copytree (Treenode* t); // used by copy constructor and operator= void destroytree (Treenode* t); // used by destructor . . . Treenode* root; };
stutree.cpp // copy constructor - for deep copies Gradetree::Gradetree (const Gradetree& othergradetree) { root = copytree (othergradetree.root); } // overload assignment for deep copies void Gradetree::operator= (const Gradetree& othergradetree) { root = copytree (othergradetree.root); }
stutree.cpp // used by copy constructor and operator= Treenode* Gradetree::copytree (Treenode* t) { Treenode* tmp = NULL; // for building copy of t if (t != NULL) { tmp = new Treenode; tmp->grade = t->grade; tmp->count = t->count; tmp->left = copytree (t->left); tmp->right = copytree (t->right); } return tmp; }
For more information • see section 6.5 in text – pp. 360 - 370