Copy Control Joe Meehean. More Class Responsibilities When making a new type (i.e., class) we must...

58
Copy Control Joe Meehean

Transcript of Copy Control Joe Meehean. More Class Responsibilities When making a new type (i.e., class) we must...

Copy Control

Joe Meehean

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

Questions?

12

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

Questions?

24

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

Questions?

35

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• Deep copying

53

Song::~Song(){ delete name_; delete artist_;}

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;}

Questions?

58