1 / 8

Memory Management with Classes

Learn about the importance of constructors, destructors, and copying in memory management with classes, including shallow vs. deep copy, heap allocation, aliasing, and scope issues.

lglenn
Download Presentation

Memory Management with Classes

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Review: for non-static built-in (native) types default constructor and destructor do nothing copy constructor and assignment operator (re-)value member-wise Review: variables vs. the pointers and references to them may have different scopes May result in obvious kinds of lifetime errors But may also introduce more subtle issues of aliasing Can risk destroying an object too soon or too late Basic ideas in memory management with classes Constructor allocates, destructor de-allocates: an object “owns” memory Shallow copy vs. deep copy: aliasing vs. duplication Memory Management with Classes

  2. Resources allocated by an object need to be freed Constructor, destructor offer good start/end points Example: class to hold a fixed sized array Can store integer values Can access each element Array size may differ for each object Once set, object’s array size is fixed #ifndef INTARRAY_H #define INTARRAY_H class IntArray { public: IntArray(size_t); ~IntArray(); int & operator[](size_t); IntArray(const IntArray &); private: size_t m_size; int *m_values; }; #endif /* INTARRAY_H */ Constructor Allocates, Destructor De-allocates

  3. Initialization list sets m_sizeto the passed length, and also sets m_valuesto0 Only allocate if length is greater than zero What does new do? Allocates memory Calls constructor(s) Destructor releases the allocated array via delete Calls elements’ destructors Returns memory to the heap #include “IntArray.h" IntArray::IntArray(size_t s) :m_size(s), m_values(0) { if (m_size > 0) { m_values = new int[m_size]; } } IntArray::~IntArray() { delete [] m_values; } int & IntArray::operator[](size_t s){ if (!m_values || s >= m_size) { throw 1; } return m_values [s]; } Constructor/Destructor, continued

  4. So, scopes are tied together IntArray and its memory What does delete do? Calls destructor(s) Frees memory What are new [] and delete [] vs. new and delete? What if m_values was 0 when delete was called on it? Remember what happens? int main(int, char*[]) { IntArray a(6); // When a is created, it // usually allocates some // memory (here, 6 ints) return 0; // Now a is destroyed, and // since it’s destructor // is called, so is the // memory it allocated } Constructor/Destructor, continued

  5. There are two ways to “copy” Shallow: aliases existing resources Deep: makes a complete and separate copy Version above shows shallow copy Efficient But may be risky. Why? Hint: destructor (how to fix?) What’s the invariant established by this code? Hint: what can we say about m_size and m_values? // just uses the array that’s already in the other object IntArray::IntArray(const IntArray &a) :m_size(a.m_size), m_values(a.m_values) { } Copy Constructor: Shallow Copy

  6. This code shows deep copy Safe: no shared aliasing But may not be very efficient Note trade-offs with arrays Allocate memory once More efficient than multiple calls to new (heap search) Constructor and assignment called on each array element Less efficient than block copy E.g., using memcpy() But sometimes more correct i.e., constructors and destructors are called // makes its own copy of the array IntArray::IntArray(const IntArray &a) :m_size(a.m_size), m_values(0) { if (m_size > 0) { m_values = new int[m_size]; for (size_t i = 0; i < m_size; ++i) { m_values[i] = a.m_values[i]; } } } Copy Constructor: Deep Copy

  7. Also Think About When to Use “new” Objects have to live beyond current scope Is object copying a viable solution? Good for copy : Card objects Object size is small Non-polymorphic Bad for copy : Player, Game objects. Involve heap memory allocation Polymorphic Is object swapping a good alternative? Good for objects with embedded heap objects such as Player, std::string All STL containers, like std::vector, std::set, std::map, …, etc. Not useful for polymorphic classes Game* makeGame(const char* name) { Game* result = 0; if (strcmp(name,”bridge”)==0) result= new BridgeGame; else if (strcmp(name,”hearts”)==0) result= new HeartsGame; return result; }

  8. Know what goes where in memory Understand the mechanics of stack vs. heap allocation Watch for simple lifetime errors Think about (and sketch) more subtle scope/lifetime issues Pay attention to aliasing issues Think about shallow copy vs. deep copy (problems/trade-offs) Summary: Memory Management With Classes

More Related