- many classes implement dynamic data structures - variable sized data
- if at all possible, use the stl
- it's all taken care of for you
- but, may be expensive in time and space, may not be possible or easy
- fixed-size blocks - may be good enough for small amounts of data
- not space efficient, but may be time efficient (implementation and run)
- not flexible, but reasonably safe with proper checking
- also known as pre-allocation
- the other possibility is to use dynamic memory - not necessarily
new
and delete
- dynamic memory and classes are not a match made in heaven - worse than
dynamic memory and exceptions; leaks o' plenty
- three class specific problems - destructors, copying, and assignments
- destructors - when an object goes out of scope (perhaps explicitly)
- pointers are basic types - they have no destructors
- nothing automatically gets done to them on destruction
- if nothing gets done to them, they create garbage - unreachable
memory
- what to do - either handle explicitly in the destructor or wrap them
in a class
- wrapping them in a class - implementing some kind of garbage
collector
- complex, mostly effective (until they're not) and powerful
- creates a destructor for pointers
- this is a common approach - auto pointers, handles, smart pointers
and, of course, the stl
- this will be taken up in the next section
- explicit destructor management - simple, effective
- the destructor calls
delete
on member pointers
- no need to check for
NULL
- a question of style
- copying - without care, class copying occurs a lot in c++
- base-type values are bit-wise copied
- replicates pointer values, leading to un-intentional sharing and
dangling pointers on destruction
- wrapping works here too, and can be efficient - copy on write
- explicitly handle the copy
- object copying is implemented by the copy constructor
T::T(const
T &)
- Each block of dynamic memory is replicated in the copy - need to keep
that information available
- assignment - also bit-wise copies base-type values
- assignment is similar to copying, but not that similar
- assignment vs. copy - redefinition vs. initialization; the state of
the target
- despite the syntax, declared variables are initialized; the target
state is undefined
- in assignment, the target is defined and is redefined - unintentional
replication and dangling pointers
- deallocate the lhs, then replicate the rhs
- assignment and copy constructors usually can share code - duplication
code is bad code
- two tricks to assignment - self assignment and the assignment
expression
- self-assignment causes problems -
a = a
- this does occur, particularly with references
- deallocating the lhs also deallocates the rhs
- check before doing the assignment -
if (&rhs != this)
- assignment is an expression -
a = b = c
- the value of an assignment is the value of the rhs
- prototype is
T & operator = (const T & rhs)
- the return value is
return *this;
- reference return type is efficient
-
T operator = (const T & rhs)
is more expensive - makes a
copy
- the rule of three
- if you need one of destructors, copy constructors, or assignment, you
need them all
- classes with visible dynamic memory members need them all
- this is non-symmetric, and not hard and fast
- a non-empty destructor implies the other two
- either the other two may or may not imply the other two
This page last modified on 27 November 2001.