From 80a8dadb824fafaefd1f0c27176bb785e1d3b186 Mon Sep 17 00:00:00 2001 From: Jidong Xiao Date: Tue, 16 Apr 2024 17:02:02 -0400 Subject: [PATCH] remove 13 --- labs/13_smart_memory/README.md | 68 ------ labs/13_smart_memory/ds_smart_pointers.h | 77 ------- labs/13_smart_memory/main_smart_pointers.cpp | 208 ------------------- labs/13_smart_memory/main_stop_and_copy.cpp | 58 ------ labs/13_smart_memory/stop_and_copy.cpp | 96 --------- labs/13_smart_memory/stop_and_copy.h | 53 ----- 6 files changed, 560 deletions(-) delete mode 100644 labs/13_smart_memory/README.md delete mode 100644 labs/13_smart_memory/ds_smart_pointers.h delete mode 100644 labs/13_smart_memory/main_smart_pointers.cpp delete mode 100644 labs/13_smart_memory/main_stop_and_copy.cpp delete mode 100644 labs/13_smart_memory/stop_and_copy.cpp delete mode 100644 labs/13_smart_memory/stop_and_copy.h diff --git a/labs/13_smart_memory/README.md b/labs/13_smart_memory/README.md deleted file mode 100644 index c384ac4..0000000 --- a/labs/13_smart_memory/README.md +++ /dev/null @@ -1,68 +0,0 @@ -# Lab 13 — Garbage Collection & Smart Pointers - -## Checkpoint 1: - -*estimate: 20-40 minutes* - -For the first checkpoint, download, compile, and run these files: [stop_and_copy.h](stop_and_copy.h), [stop_and_copy.cpp](stop_and_copy.cpp), [main_stop_and_copy.cpp](main_stop_and_copy.cpp) - -In Lecture 25, we stepped through the Stop and Copy garbage collection algorithm on a small example. -Examine the output of the program to see a computer simulation of this same example. Verify that the -program behaves as we predicted in lecture. - -Continuing with the same example, 3 more nodes have been added and the garbage collector must be run -again. Draw a “box and pointer” diagram (the more usual human-friendly version of the interconnected -node structure with few or no crossing pointer arrows) of the memory accessible from the root pointer after -these 3 nodes are added and work through the Stop and Copy algorithm for this example on paper. When -you are finished, uncomment the simulation and check your work. - -**To complete this checkpoint**: Show (and explain to) one of the TAs your box and pointer diagram. - -## Checkpoint 2: - -*estimate: 20-40 minutes* - -The theme for this checkpoint are the helium filled balloons for the Macy’s Thanksgiving Day parade. These -balloons are held in place by one or more ropes held by people on the ground. Alternately, balloons may -be connected to other balloons that are held by people! People can swap which balloon they are holding -on to, but if everyone holding on to the ropes for a particular balloon lets go, we will have a big problem! -Download, compile, and run these files: [ds_smart_pointers.h](ds_smart_pointers.h) and [main_smart_pointers.cpp](main_smart_pointers.cpp). -Use Dr. Memory or Valgrind to inspect the initial code for memory errors and/or memory leaks. - -Carefully examine the example allocations in the main function of the provided code. Draw simple pictures -to help keep track of which objects have been allocated with new, and which variables currently point to -each dynamically allocated object. - -To fix the memory leaks in this program, you will need to add explicit deallocation for the non-smart pointer -examples (marked CHECKPOINT 2A and 2B). For comparison, the code includes simple examples of smart -pointers for these objects as well! When we know that just one person will hold on to a Balloon at a time -(one owner) we can use a dsAutoPtr (see also the STL auto_ptr or STL unique_ptr, depending on your -version of g++/clang/STL). When multiple people might hold ropes to the same Balloon, we should use a -dsSharedPtr (see also STL shared_ptr or Boost shared_ptr). A shared pointer uses reference counting! -When the last person disconnects from a Balloon using a shared pointer, the Balloon is automatically deleted. - -Re-compile & re-run with the memory debugger to confirm you have fixed the simple leaks. For the final -piece of this checkpoint (marked CHECKPOINT 2C), you must also re-rewrite the interconnected balloon -example to use shared pointers. You will need to modify the Balloon class to use dsSharedPointer as well. - -**To complete this checkpoint**: Explain to your TA the code you needed to add and/or modify to correct -the memory leaks in the provided code. Show your TA the result of the memory debugger on your finished -implementation. - -## Checkpoint 3: - -*estimate: 20-40 minutes* - -For the last checkpoint, let’s consider cyclic balloon structures. A simple example is included at the bottom -of main_smart_pointer.cpp. Draw a diagram of this structure on paper. The provided code has memory -leaks for this example. We could try to re-write this example to use the shared smart pointer. However, a -reference counting smart pointer will still have a problem on this cyclic example. Why? - -Instead, let’s write a helper function to explicitly deallocate a general cyclic structure of Balloon objects. (We -will not use smart pointers for this checkpoint). You should switch back to the original Balloon class (if you -modified it for Checkpoint 2). You will first need to collect all nodes that are reachable from the provided -argument. Make sure that you do not enter an infinite loop when tracing through the structure! You may -find std::set helpful. Once you have identified all of the nodes that are accessible from the input argument, -you can call delete on each Node. Write additional test cases to confirm that your code is debugged. - -**To complete this checkpoint**: Show the TA cyclic memory diagram, your debugged implementation, and the memory debugger output to confirm that your code has no memory errors or leaks. diff --git a/labs/13_smart_memory/ds_smart_pointers.h b/labs/13_smart_memory/ds_smart_pointers.h deleted file mode 100644 index 7f19b7a..0000000 --- a/labs/13_smart_memory/ds_smart_pointers.h +++ /dev/null @@ -1,77 +0,0 @@ -#include - -// ============================================================================== -// basic auto pointer implementation -// see also http://ootips.org/yonat/4dev/smart-pointers.html - -template -class dsAutoPtr { -public: - explicit dsAutoPtr(T* p = NULL) : ptr(p) {} /* prevents cast/conversion */ - ~dsAutoPtr() { delete ptr; } - T& operator*() { return *ptr; } - T* operator->() { return ptr; } -private: - T* ptr; -}; - - -// ============================================================================== -// basic reference counting pointer borrowed from: -// http://www.codeproject.com/Articles/15351/Implementing-a-simple-smart-pointer-in-c - -class ReferenceCount { -public: - ReferenceCount() { count = 0; } - void addReference() { count++; } - int releaseReference() { return --count; } -private: - int count; -}; - - -template -class dsSharedPtr { -public: - dsSharedPtr(T* pValue = NULL) : pData(pValue) { - // Create a new reference counter & increment the count - reference = new ReferenceCount(); - reference->addReference(); - } - dsSharedPtr(const dsSharedPtr& sp) : pData(sp.pData), reference(sp.reference) { - // use the same reference counter, increment the count - reference->addReference(); - } - dsSharedPtr& operator= (const dsSharedPtr& sp) { - if (this != &sp) { - // Decrement the old reference count - // if reference become zero delete the old data - if(reference->releaseReference() == 0) { - delete pData; - delete reference; - } - // Copy the data and reference pointer - // and increment the reference count - pData = sp.pData; - reference = sp.reference; - reference->addReference(); - } - return *this; - } - // destructor - ~dsSharedPtr() { - if (reference->releaseReference() == 0) { - delete pData; - delete reference; - } - } - bool operator== (const dsSharedPtr& sp) { return pData == sp.pData; } - T& operator* () { return *pData; } - T* operator-> () { return pData; } -private: - // REPRESENTATION - T* pData; - ReferenceCount* reference; -}; - -// ============================================================================== diff --git a/labs/13_smart_memory/main_smart_pointers.cpp b/labs/13_smart_memory/main_smart_pointers.cpp deleted file mode 100644 index 709789d..0000000 --- a/labs/13_smart_memory/main_smart_pointers.cpp +++ /dev/null @@ -1,208 +0,0 @@ -#include -#include -#include - -// simple homemade smart pointers -#include "ds_smart_pointers.h" - - -// ==================================================== -// BALLOON: a toy class with dynamically allocated memory -// ==================================================== - -#define MAX_NUM_ROPES 10 - -class Balloon { -public: - // CONSTRUCTOR & DESTRUCTOR - Balloon(const std::string& name_) : name(name_) { - std::cout << "Balloon constructor " << name << std::endl; - num_ropes = 0; - ropes = new Balloon*[MAX_NUM_ROPES]; - } - ~Balloon() { - std::cout << "Balloon destructor " << name << std::endl; - // don't try to destroy attached balloons, just delete array - delete [] ropes; - } - - // ACCESSORS - const std::string& getName() const { return name; } - int numRopes() const { return num_ropes; } - const Balloon* getRope(int i) const { return ropes[i]; } - - // print the balloons we are attached to - void print() { - std::cout << "Balloon " << name << " is connected to: "; - for (int i = 0; i < num_ropes; i++) { - std::cout << ropes[i]->name << " "; - } - if (num_ropes == 0) std::cout << "nothing"; - std::cout << std::endl; - } - // add a rope connecting this balloon to another - void addRope(Balloon* b) { - assert (num_ropes < MAX_NUM_ROPES); - ropes[num_ropes] = b; - num_ropes++; - } - // detach a rope connecting this balloon to another - void removeRope(Balloon* b) { - for (int i = 0; i < MAX_NUM_ROPES; i++) { - if (ropes[i] == b) { ropes[i] = ropes[num_ropes-1]; num_ropes--; break; } - } - } - -private: - std::string name; - int num_ropes; - // a dynamically allocated C-style array of ropes connecting to other Balloons - Balloon** ropes; -}; - - -// ==================================================== -// ==================================================== - -int main() { - - std::cout << "start of main" << std::endl; - - // ==================================================== - // SINGLE OWNER SMART POINTERS - // ==================================================== - - // first, without smart pointers! - Balloon* alice(new Balloon("Hello Kitty")); - - // now, with our homemade single owner smart pointer - dsAutoPtr bob(new Balloon("Spiderman")); - - // both alice & bob work like regular pointers... - alice->print(); - bob->print(); - - - - // - // CHECKPOINT 2A: INSERT NECESSARY EXPLICIT DEALLOCATION - // - - - - // ==================================================== - // SIMPLE SHARED POINTERS - // ==================================================== - - // first, without smart pointers - Balloon* cathy(new Balloon("Buzz Lightyear")); - Balloon* daniel(cathy); - Balloon* elaine(new Balloon("Pokemon")); - Balloon* fred(elaine); - daniel = fred; - fred = NULL; - elaine = cathy; - cathy = NULL; - - - - // - // CHECKPOINT 2B: INSERT NECESSARY EXPLICIT DEALLOCATION - // - - - - daniel = NULL; - elaine = NULL; - - - // now, with our homemade shared pointer - dsSharedPtr cathy2(new Balloon("Buzz Lightyear2")); - dsSharedPtr daniel2(cathy2); - dsSharedPtr elaine2(new Balloon("Pokemon2")); - dsSharedPtr fred2(elaine2); - daniel2 = fred2; - fred2 = NULL; - elaine2 = cathy2; - cathy2 = NULL; - // NOTE: no explicit destruction required! - daniel2 = NULL; - elaine2 = NULL; - - - // ==================================================== - // SHARED POINTERS WITH INTERCONNECTED STRUCTURES - // ==================================================== - - Balloon* georgette(new Balloon("Mr Potato Head")); - Balloon* henry(new Balloon("Snoopy")); - - georgette->addRope(henry); - henry = new Balloon("Tigger"); - georgette->addRope(henry); - georgette->print(); - henry->print(); - - Balloon* isabelle(new Balloon("Shrek")); - henry->addRope(isabelle); - isabelle = new Balloon("Barney the Purple Dinosaur"); - georgette->addRope(isabelle); - - henry->print(); - georgette->print(); - isabelle->print(); - - - // - // CHECKPOINT 2C: REWRITE THE ABOVE EXAMPLE TO USE SHARED POINTERS - // - - - - // ==================================================== - // CYCLIC STRUCTURES - // ==================================================== - - - // FOR CHECKPOINT 3 - - - /* - Balloon* jacob(new Balloon("Dora the Explorer")); - Balloon* katherine(new Balloon("Kung Fu Panda")); - Balloon* larry(new Balloon("Scooby Doo")); - Balloon* miranda(new Balloon("SpongeBob SquarePants")); - Balloon* nicole(new Balloon("Papa Smurf")); - - jacob->addRope(katherine); - katherine->addRope(larry); - larry->addRope(jacob); - miranda->addRope(jacob); - nicole->addRope(miranda); - larry->addRope(nicole); - - katherine = NULL; - larry = NULL; - miranda = NULL; - nicole = NULL; - - // jacob points to a cyclic structure! - - // to cleanup this structure: - deleteAll(jacob); - - jacob = NULL; - */ - - - - std::cout << "end of main" << std::endl; - return 0; - - // - // NOTE: when smart pointers go out of scope, the destructors for - // those objects will be called automatically - // -} - -// ==================================================== diff --git a/labs/13_smart_memory/main_stop_and_copy.cpp b/labs/13_smart_memory/main_stop_and_copy.cpp deleted file mode 100644 index 80e62e5..0000000 --- a/labs/13_smart_memory/main_stop_and_copy.cpp +++ /dev/null @@ -1,58 +0,0 @@ -#include -#include -#include "stop_and_copy.h" - - -int main() { - - StopAndCopy m; - std::cout << "TESTING StopAndCopy" << std::endl; - std::cout << std::endl << "empty memory:" << std::endl << m; - - // create an interesting data structure - m.root = m.my_new('a',MY_NULL,MY_NULL); - m.my_new('b',MY_NULL,m.root); - m.root = m.my_new('c',m.root,MY_NULL); - m[m.root].right = m.my_new('d',m[m.root].left,MY_NULL); - - std::cout << std::endl << "4 cells allocated:" << std::endl << m; - - m.root = m.my_new('e',MY_NULL,m.root); - m[m.root].right = m.my_new('f',m[m.root].right,MY_NULL); - m[m[m.root].right].right = m.my_new('g',m[m.root].right,MY_NULL); - m.root = m.my_new('h',m.root,MY_NULL); - m.root = m[m[m.root].left].right; - - std::cout << std::endl << "8 cells allocated:" << std::endl << m; - - // force garbage collection - m.collect_garbage(); - std::cout << std::endl << "after forced garbage collection:" << std::endl << m; - - // allocate more cells to force garbage collection - m[m.root].left = m.my_new('i',m.root,MY_NULL); - m.root = m.my_new('j',m.root,MY_NULL); - m.root = m.my_new('k',m.root,MY_NULL); - - std::cout << std::endl << "after adding 3 more cells:" << std::endl << m; - - - // Walk through the Stop And Copy garbage collection algorithm on - // the memory at this point in the program. Draw a pencil & paper - // diagram to show your work. - - - // UNCOMMENT THESE LINES AFTER YOU FINISH CHECKPOINT 1 (to check your work) - /* - m.root = m.my_new('l',m.root,MY_NULL); - std::cout << std::endl << "adding another cell triggers automatic garbage collection:" << std::endl << m; - - // "forget" the root pointer - m.root = MY_NULL; - m.collect_garbage(); - std::cout << std::endl << "root set to null & forced garbage collection:" << std::endl << m; - */ - -} - -// ============================================================================== diff --git a/labs/13_smart_memory/stop_and_copy.cpp b/labs/13_smart_memory/stop_and_copy.cpp deleted file mode 100644 index 5c4b90c..0000000 --- a/labs/13_smart_memory/stop_and_copy.cpp +++ /dev/null @@ -1,96 +0,0 @@ -#include "stop_and_copy.h" - - -// Return the node corresponding to a particular address -Node& StopAndCopy::operator[](Address addr) { - if (addr == MY_NULL) { - std::cerr << "ERROR: NULL POINTER EXCEPTION!" << std::endl; exit(1); } - if (addr < OFFSET || addr >= OFFSET+CAPACITY) { - std::cerr << "ERROR: SEGMENTATION FAULT!" << std::endl; exit(1); } - return memory[addr-OFFSET]; -} - - -Address StopAndCopy::my_new(char v, Address l, Address r) { - // if we are out of memory, collect garbage - if (next == partition_offset+CAPACITY/2) { - collect_garbage(); - // update the addresses (since memory has been shuffled!) - if (l != MY_NULL) l = memory[l-OFFSET].left; - if (r != MY_NULL) r = memory[r-OFFSET].left; - } - // if we are still out of memory, we can't continue - if (next == partition_offset+CAPACITY/2) { - std::cerr << "ERROR: OUT OF MEMORY!" << std::endl; exit(1); } - // assign the next available node - memory[next].value = v; - memory[next].left = l; - memory[next].right = r; - return OFFSET + next++; -} - - -// Print function for debugging -std::ostream& operator<<(std::ostream &ostr, StopAndCopy &m) { - ostr << "root-> " << m.root << std::endl; - for (int i = 0; i < CAPACITY; i++) { - ostr.width(4); ostr << i+OFFSET << " "; } - ostr << std::endl; - for (int i = 0; i < CAPACITY; i++) { - ostr << " "; ostr.width(1); ostr << m.memory[i].value << " "; } - ostr << std::endl; - for (int i = 0; i < CAPACITY; i++) { - ostr.width(4); ostr << m.memory[i].left << " "; } - ostr << std::endl; - for (int i = 0; i < CAPACITY; i++) { - ostr.width(4); ostr << m.memory[i].right << " "; } - ostr << std::endl; - // print "FREE" or "used" for each node in the current partition - for (int i = 0; i < CAPACITY; i++) { - if (i >= m.next && i < m.partition_offset+CAPACITY/2) - ostr << "FREE "; - else if (i >= m.partition_offset && i < m.partition_offset+CAPACITY/2) - ostr << "used "; - else // print nothing for the other half of memory - ostr << " "; } - ostr << std::endl; - return ostr; -} - - -void StopAndCopy::collect_garbage() { - // switch to the other partition - partition_offset = (partition_offset == 0) ? CAPACITY/2 : 0; - // scan & next start at the beginning of the new partition - Address scan; - next = scan = partition_offset; - // copy the root - copy_help(root); - // scan through the newly copied nodes - while (scan != next) { - // copy the left & right pointers - copy_help(memory[scan].left); - copy_help(memory[scan].right); - scan++; - } -} - - -void StopAndCopy::copy_help(Address &old) { - // do nothing for NULL Address - if (old == MY_NULL) return; - // look for a valid forwarding address to the new partition - int forward = memory[old-OFFSET].left; - if (forward-OFFSET >= partition_offset && - forward-OFFSET < partition_offset+CAPACITY/2) { - // if already copied, change pointer to new address - old = forward; - return; - } - // otherwise copy it to a free slot and leave a forwarding address - memory[next] = memory[old-OFFSET]; - memory[old-OFFSET].left = next+OFFSET; - old = next+OFFSET; - next++; -} - diff --git a/labs/13_smart_memory/stop_and_copy.h b/labs/13_smart_memory/stop_and_copy.h deleted file mode 100644 index 4523bb2..0000000 --- a/labs/13_smart_memory/stop_and_copy.h +++ /dev/null @@ -1,53 +0,0 @@ -#include - -// size of memory available for this process -#define CAPACITY 16 -// first valid address for this process -#define OFFSET 100 -#define MY_NULL 0 - - -typedef int Address; - - -// A helper class for the StopAndCopy memory system -class Node { -public: - Node() { value='?'; left=-1; right=-1; } // initialized with "garbage" values - char value; - Address left; - Address right; -}; - - -// A simple implementation of the basic StopAndCopy garbage collector -class StopAndCopy { -public: - StopAndCopy() { - root = MY_NULL; - partition_offset = 0; - next = 0; - } - // Return the node corresponding to a particular address - Node& operator[](Address addr); - // allocate a new node - Address my_new(char v, Address l, Address r); - // a print function for debugging - friend std::ostream& operator<<(std::ostream &ostr, StopAndCopy &m); - // force automatic memory management - void collect_garbage(); - // REPRESENTATION -public: - // the user must set this value such that all useful memory is - // reachable starting from root (NOTE: publicly accessible) - Address root; -private: - // total machine memory - Node memory[CAPACITY]; - // which half of the memory is active - int partition_offset; - // next available node - int next; - // a private helper function - void copy_help(Address &old_address); -};