Copy Control Joe Meehean. More Class Responsibilities When making a new type (i.e., class) we must...
-
Upload
isaac-parker -
Category
Documents
-
view
217 -
download
0
Transcript of Copy Control Joe Meehean. More Class Responsibilities When making a new type (i.e., class) we must...
More Class Responsibilities• When making a new type (i.e., class) we must specify what
happens when it is:• Copied• Assigned• Destroyed
2
Copy Constructor• Used to create a new copy of a class object• Takes a single parameter of same class type (usually const)• Has no return type• Declaration syntax• Class(const Class& orig)• e.g., IntMatrix(const IntMatrix& orig);
3
Copy Constructor• Usage syntax• Class varname(origname)• e.g.,
IntMatrix a(4,4);IntMatrix b(a);
• Definition requirements• must initialize all data members• data members should match values of original’s data members
4
Copy Constructor
5
// (header) .hclass HitSong{ Song hit_song_; int chart_rank_; int singles_sold_;
HitSong( Song& song, int chart_rank, int singles_sold);
HitSong( const HitSong& orig);};
Copy Constructor
6
HitSong::HitSong(const HitSong& orig) :hit_song_(orig.hit_song_),chart_rank_(orig.chart_rank_),singles_sold_(orig.singles_sold_)
{ // nothing to do here}
• Note: this constructor can access private data of orig• Because both this and orig are instances of HitSong
Copy Constructor• What if we don’t write a copy constructor?• Compiler creates one for us• called the synthesized copy constructor• created even if we define other constructors
• Synthesized copy constructor• performs memberwise initialization of member data• initializes each member variable by copying original
member variable• if member variable is a built-in (primitive), just copies the bits• if member variable is a class, uses the class’s copy constructor• if member variable is an array, copies each element 7
Copy Constructor• How do we prevent copies of our class?• Approach 1: make copy constructor private• prevents non-class code from making copies• friends and member functions of class can still make copies
• Approach 2: make undefined, private copy constructor• declare it
• e.g., IntMatrix(const IntMatrix& orig);• do not define it• perfectly legal• non-class code gets compiler errors• class code and friends get linking errors 8
Copy Constructor• When is it used• Explicitly in code• e.g., IntMatrix b(a);
• Passing class instance as an argument to a function• non-reference• e.g., flip(IntMatrix a);
• Returning a non-reference instance from a function• e.g., return a;
9
Copy Constructor• When is it used• Explicitly initializing an array
10
Song songs[] = { Song(“Simply Irresistable”, “Robert Palmer”), Song(“The Power of Love”, “Huey Lewis & The News”), Song(“In the Air Tonight”, “Phil Collins”)};
• Uses constructor to create temporary Songs • Initializes array using copies of temporary Songs
Copy Constructor• Classes best practices: always define a • default constructor• copy constructor
11
Assignment Operator• If you implement a class,
you need to control what happens during an assignment• e.g., b = a;• make sure data is copied correctly from a to b
• How do we write a function for an operator?
13
Assignment Operator• How do we write a function for an operator?• syntax:
return_type operator symbol(type operand1, type operand 2, …)• e.g.,
int operator + ( const int& a, const int& b);• The assignment operator (=) often returns a reference to the
assigned variable• allows: a = b = c;• e.g.,
int& operator = (int& a, int& b);• More on this in future lectures
14
Assignment Operator• When we write an operator function for a class,
the first parameter is implicitly the this parameter
• Assignment operator for a class declaration syntax• Class& operator =(const Class& rhs)• e.g., HitSong& operator =(const HitSong& rhs)
• Assignment operator for a class definition syntax• Class& Class::operator =(const Class& rhs){ … }• e.g., HitSong& HitSong::operator =(const HitSong& rhs)
15
Assignment Operator• When doing assignment we are copying values from one
instance of a class to another• unlike copy constructor, both instances are already initialized
16
Song aSong(“Twilight Zone”, “Golden Earring”);Song bSong(“Radar Love”, “Golden Earring”);
aSong = bSong;
Assignment Operator
17
HitSong& HitSong::operator =(const HitSong& rhs){ if( this != &rhs ){
this->song_ = rhs.song_; this->chart_rank_ = rhs.chart_rank_; this->singles_sold_ = rhs.singles_sold_;
}
return *this;}
Assignment Operator
18
HitSong& HitSong::operator =(const HitSong& rhs){ if( this != &rhs ){
this->song_ = rhs.song_; this->chart_rank_ = rhs.chart_rank_; this->singles_sold_ = rhs.singles_sold_;
}
return *this;}
Assignment Operator
19
HitSong& HitSong::operator =(const HitSong& rhs){ if( this != &rhs ){
this->song_ = rhs.song_; this->chart_rank_ = rhs.chart_rank_; this->singles_sold_ = rhs.singles_sold_;
}
return *this;}
Assignment Operator• What if we don’t write an assignment operator?
• Compiler makes a synthesized assignment operator• Performs memberwise assignment• each member variable is assigned member variable from rhs• built-ins use a bitwise assignment• classes uses their own assignment operator• arrays are assigned element by element
• Returns *this
20
Assignment Operator• What happens in this code?
21
Song aSong(“Hotel California”, “Eagles”);Song b = aSong;
Assignment Operator• What happens in this code?
22
Song aSong(“Hotel California”, “Eagles”);Song b = aSong;
• b is created using Song’s copy constructor
Assignment Operator• Classes best practices: always define a • default constructor• copy constructor• assignment operator
23
Destructor• How do we clean up the memory we allocated with
the constructor?
• Each class needs a destructor method• one more responsibility of class creator• specifies how to clean up memory allocated for member data• complement of constructors
25
Destructor• When is the destructor called?
• Automatic objects• automatically destroyed when they go out of scope
26
int HitSong::func(){ Song aSong(“Could well be in”, “The Streets”); // other stuff ...}
aSong is destroyed using its destructor
Destructor• When is the destructor called?
• Dynamically allocated objects• destroyed explicitly using delete
27
int HitSong::func(){ Song * pSong = new Song( “Could well be in”,
“The Streets”); // other stuff ... delete pSong;}
Memory pointed to by pSong is destroyed using its destructor
Destructor• When is the destructor called?
• Dynamically allocated objects• if never deleted, it is never destroyed
28
int HitSong::func(){ Song * pSong = new Song( “Could well be in”,
“The Streets”); // other stuff ...}
pSong lives on forever. We cannot get access to it either.
Destructor• When is the destructor called?
• Arrays of objects • deleted when array is destroyed
29
int HitSong::func(){ Song songs[10]; // other stuff ...}
each Song in songs is destroyed using its destructor
Destructor• Declaration syntax• virtual ~Class();• e.g., virtual ~Song();• takes no parameters• has not return type• ignore what virtual means for now, just include it
• Definition syntax• Class::~Class(){• e.g., Song::~Song(){
30
Destructor• Usage syntax• how do we call the destructor• you don’t, its called automatically in cases described earlier
31
Destructor• What happens if we don’t define one?• Compiler defines a destructor for you.• destroys each non-static member variable• using same rules like the object went out of scope• destroys them in reverse order of declaration
• What happens if we do define one• compiler defines one even if you define one too• compiler runs its destructor after yours
32
Destructor• Why bother to define a destructor if the compiler already does
it for you?• May need to deallocate non-automatic resources• dynamically allocated memory• close open files• amongst others (more on this in OS)
• What should our destructor do?• if you don’t dynamically allocate memory (or other resources)• nothing
33
Destructor• Classes best practices: always define a • default constructor• copy constructor• assignment operator• destructor
• Actually…• you should decide for yourself, except• Big Three: copy constructor, assignment operator, and destructor• if you define a one of Big Three, should always define other two
34
Copy Control and Pointers• Pointers make copy control (Big Three) more difficult• Class designer must make one of two choices:• Shallow copy• copy and assignment should copy only the pointer
• Deep copy• copy and assignment allocate new memory and copy object
pointer points to
36
Copy Control and Pointers• Assume
37
Song::Song( const char* name, const char *artist){ name_ = new char[512]; // SHOULD USE STRLEN artist_ = new char[512]; strcpy(name_, name); strcpy(artist_, artist);}
void Song::setArtist(const char* artist){ strcpy(artist_, artist); // SHOULD CHECK LENGTH}
void Song::deleteName(){ delete name_; name_ = NULL;}
Copy Control and Pointers• Shallow copying
38
Song::Song(const Song& orig){ name_ = orig.name_; artist_ = orig.artist_;}
Copy Control and Pointers• Shallow copying
39
void main(){ Song aSong(“All along the watchtower”,
“Bob Dylan”);}
Bob Dylan
All along…
aSong :
name_
artist_
Copy Control and Pointers• Shallow copying
40
void main(){ Song aSong(“All along the watchtower”,
“Bob Dylan”);
Song bSong(aSong);}
Bob Dylan
All along…
bSong :
name_
artist_
aSong :
name_
artist_
Copy Control and Pointers• Shallow copying
41
void main(){ Song aSong(“All along the watchtower”,
“Bob Dylan”);
Song bSong(aSong);
aSong.setArtist(“Jimi Hendrix”);}
Jimi Hendrix
All along…
bSong :
name_
artist_
aSong :
name_
artist_
Copy Control and Pointers• Shallow copying
42
void main(){ Song aSong(“All along the watchtower”,
“Bob Dylan”);
Song bSong(aSong);
aSong.setArtist(“Jimi Hendrix”); aSong.deleteName();}
Jimi Hendrix
All along…
bSong :
name_
artist_
aSong :
name_
artist_
Director’s Cut
Copy Control and Pointers• Dangers of shallow copies• data modified out from under you• data destroyed, left pointing at garbage• program crashes or acts strangely
43
Copy Control and Pointers• Deep copying
44
Song::Song(const Song& orig){ name_ = new char[strlen(orig.name_)+1]; artist_ = new char[strlen(orig.artist_)+1]; strcpy(name_, orig.name_); strcpy(artist_, orig.artist_);}
Copy Control and Pointers• Deep copying
45
void main(){ Song aSong(“All along the watchtower”,
“Bob Dylan”);}
Bob Dylan
All along…
aSong :
name_
artist_
Copy Control and Pointers• Deep copying
46
void main(){ Song aSong(“All along the watchtower”,
“Bob Dylan”);
Song bSong(aSong);}
Bob Dylan
All along…
bSong :
name_
artist_
aSong :
name_
artist_Bob Dylan
All along…
Copy Control and Pointers• Deep copying
47
void main(){ Song aSong(“All along the watchtower”,
“Bob Dylan”);
Song bSong(aSong);
aSong.setArtist(“Jimi Hendrix”);}
Jimi Hendrix
All along…
bSong :
name_
artist_
aSong :
name_
artist_Bob Dylan
All along…
Copy Control and Pointers• Deep copying
48
void main(){ Song aSong(“All along the watchtower”,
“Bob Dylan”);
Song bSong(aSong);
aSong.setArtist(“Jimi Hendrix”); aSong.deleteName();}
Jimi Hendrix
All along…
bSong :
name_
artist_
aSong :
name_
artist_Bob Dylan
All along…
Director’s Cut
Copy Control and Pointers• If you don’t define a copy constructor or an
assignment operator• synthesized versions perform a shallow copy
• If you define a deep copy constructor and assignment operator, but not a destructor• you will leak memory
49
Copy Control and Pointers• Deep copying
50
Song::operator =(const Song& orig){ if( this != &orig ){ delete name_; delete artist_;
name_ = new char[strlen(orig.name_)+1]; artist_ = new char[strlen(orig.artist_)+1]; strcpy(name_, orig.name_); strcpy(artist_, orig.artist_); } return *this;}
Copy Control and Pointers• Deep copying
51
Song::operator =(const Song& orig){ if( this != &orig ){ delete name_; delete artist_;
name_ = new char[strlen(orig.name_)+1]; artist_ = new char[strlen(orig.artist_)+1]; strcpy(name_, orig.name_); strcpy(artist_, orig.artist_); } return *this;}
Copy Control and Pointers• Deep copying
52
Song::operator =(const Song& orig){ if( this != &orig ){ delete name_; delete artist_;
name_ = new char[strlen(orig.name_)+1]; artist_ = new char[strlen(orig.artist_)+1]; strcpy(name_, orig.name_); strcpy(artist_, orig.artist_); } return *this;}
Copy Control and Pointers• When a shallow copy is really a deep copy• if the member object is not really owned by this class• if we just have a reference to another objects data, we should not
copy it or destroy it
• How can I tell if my class owns an object?• if you created it or are going to destroy it, it is yours• if you new’ed it, you should delete it• if you are going to delete it, you should new it
54
Copy Control and Pointers• When a shallow copy is really a deep copy• which class owns which
55
class Song{ char *name_; char *artist_; Album *album_;};
class Album{ Song *songs_; int number_of_songs;};
Copy Control and Pointers• Deep copying that looks shallow
56
Song::operator =(const Song& orig){ if( this != &orig ){ delete name_; delete artist_;
name_ = new char[strlen(orig.name_)+1]; artist_ = new char[strlen(orig.artist_)+1]; strcpy(name_, orig.name_); strcpy(artist_, orig.artist_);
album_ = orig.album_; } return *this;}
Copy Control and Pointers• Deep copying
57
Album::operator =(const Album& orig){ if( this != &orig ){ delete songs_; number_of_songs_ = orig.number_of_songs; songs_ = new Song[number_of_songs]; for(int i = 0; i < number_of_songs; i++){ songs_[i] = origs.songs_[i]; songs_[i].album = this; } } return *this;}