Copying Data. Contents. Steven J. Zeil. November 13, Destructors 2

Similar documents
Operator Overloading

Operator Overloading

Encapsulation. Contents. Steven Zeil. July 17, Encapsulation Encapsulation in C Classes 4. 3 Hiding Attributes 8

Unit Testing. Contents. Steven Zeil. July 22, Types of Testing 2. 2 Unit Testing Scaffolding Drivers Stubs...

Unit Testing. Steven Zeil. July 22, Types of Testing 2. 2 Unit Testing Scaffolding Drivers Stubs...

Common Modifications of Class Members

Common Modifications of Class Members

Common Modifications of Class Members

Defensive Programming

The Structure of a C++ Program

Linked Lists. Contents. Steven J. Zeil. July 31, Linked Lists: the Basics 4

Linked Lists. Contents. Steven J. Zeil. July 31, Linked Lists: the Basics 3

The Structure of a C++ Program

Pointers and References

CPSC 427: Object-Oriented Programming

04-19 Discussion Notes

2 ADT Programming User-defined abstract data types

Special Member Functions. Compiler-Generated Destructor. Compiler-Generated Default Constructor. Special Member Functions

A C++ Class Designer s Checklist

Special Member Functions

INITIALISING POINTER VARIABLES; DYNAMIC VARIABLES; OPERATIONS ON POINTERS

Class Vector: Interface CSE 143. Dynamic Memory In Classes [Chapter 4, p ] Vector Implementation. Many Ways to Implement. Draw the picture!

And Even More and More C++ Fundamentals of Computer Science

CSE 333. Lecture 11 - constructor insanity. Hal Perkins Paul G. Allen School of Computer Science & Engineering University of Washington

More About Classes. Gaddis Ch. 14, CS 2308 :: Fall 2015 Molly O'Neil

More class design with C++ Starting Savitch Chap. 11

COMP6771 Advanced C++ Programming

Short Notes of CS201

Assignment of Structs

CS201 - Introduction to Programming Glossary By

3.Constructors and Destructors. Develop cpp program to implement constructor and destructor.

Lab 2: ADT Design & Implementation

PIC 10A Objects/Classes

See the CS 2704 notes on C++ Class Basics for more details and examples. Data Structures & OO Development I

CPSC 427: Object-Oriented Programming

Fast Introduction to Object Oriented Programming and C++

Introducing C++ to Java Programmers

EECE.3220: Data Structures Spring 2017

III. Classes (Chap. 3)

QUIZ. What is wrong with this code that uses default arguments?

Patterns: Working with Arrays

Intermediate Programming, Spring 2017*

COMP6771 Advanced C++ Programming

QUIZ on Ch.5. Why is it sometimes not a good idea to place the private part of the interface in a header file?

Lecture 7. Log into Linux New documents posted to course webpage

Ch. 11: References & the Copy-Constructor. - continued -

Object-Oriented Principles and Practice / C++

ADTs in C++ In C++, member functions can be defined as part of a struct

CSE 374 Programming Concepts & Tools. Hal Perkins Fall 2015 Lecture 19 Introduction to C++

MARKING KEY The University of British Columbia MARKING KEY Computer Science 260 Midterm #2 Examination 12:30 noon, Thursday, March 15, 2012

Programming in C ++ Prof. Partha Pratim Das Department of Computer Science and Engineering Indian Institute of Technology, Kharagpur

Slide Set 14. for ENCM 339 Fall Steve Norman, PhD, PEng. Electrical & Computer Engineering Schulich School of Engineering University of Calgary

MARKING KEY The University of British Columbia MARKING KEY Computer Science 260 Midterm #1 Examination 12:30 noon, Tuesday, February 14, 2012

2. It is possible for a structure variable to be a member of another structure variable.

CSE 374 Programming Concepts & Tools. Hal Perkins Spring 2010

The issues. Programming in C++ Common storage modes. Static storage in C++ Session 8 Memory Management

explicit class and default definitions revision of SC22/WG21/N1582 =

Object Oriented Programming COP3330 / CGS5409

A class is a user-defined type. It is composed of built-in types, other user-defined types and

Operator Overloading in C++ Systems Programming

Computer Programming with C++ (21)

05-01 Discussion Notes

Object-Oriented Programming for Scientific Computing

CSCE 110 PROGRAMMING FUNDAMENTALS

Dynamic memory in class Ch 9, 11.4, 13.1 & Appendix F

Inheritance and Polymorphism

QUIZ How do we implement run-time constants and. compile-time constants inside classes?

CSI33 Data Structures

Instantiation of Template class

Operator overloading

Lecture 8. Xiaoguang Wang. February 13th, 2014 STAT 598W. (STAT 598W) Lecture 8 1 / 47

QUIZ Friends class Y;

Chapter 13: Copy Control. Overview. Overview. Overview

CS24 Week 3 Lecture 1

CE221 Programming in C++ Part 1 Introduction

SFU CMPT Topic: Classes

CSE 303: Concepts and Tools for Software Development

A Deeper Look at Classes

Data Structures and Other Objects Using C++

C++ Constructor Insanity

Object Oriented Design

Object-Oriented Principles and Practice / C++

the gamedesigninitiative at cornell university Lecture 7 C++ Overview

Software Engineering Concepts: Invariants Silently Written & Called Functions Simple Class Example

G52CPP C++ Programming Lecture 9

Vector and Free Store (Vectors and Arrays)

CSS 342 Data Structures, Algorithms, and Discrete Mathematics I. Lecture 2. Yusuf Pisan

QUIZ. What are 3 differences between C and C++ const variables?

Practice Problems CS2620 Advanced Programming, Spring 2003

Chapter 2. Procedural Programming

Programmazione. Prof. Marco Bertini

CS 1337 Computer Science II Page 1

G52CPP C++ Programming Lecture 13

Chapter 1 Getting Started

Shahram Rahatlou. Computing Methods in Physics. Overloading Operators friend functions static data and methods

Suppose we find the following function in a file: int Abc::xyz(int z) { return 2 * z + 1; }

Class Destructors constant member functions

Assignment of Objects

COMP6771 Advanced C++ Programming

C++ Object-Oriented Programming

Transcription:

Steven J. Zeil November 13, 2013 Contents 1 Destructors 2 2 Copy Constructors 11 2.1 Where Do We Use a Copy Constructor? 12 2.2 Compiler-Generated Copy Constructors............................................ 13 2.3 Example: Bid: Compiler-Generated Copy Constructor.................................... 13 2.4 Example: BidCollection: Compiler-Generated Copy Constructor.............................. 14 2.5 Writing a BidCollection Copy Constructor........................................... 23 2.6 Shallow & Deep Copying......... 28 3 Assignment 30 3.1 Compiler-Generated Assignment Ops. 30 3.2 Implementing Assignment....... 35 4 The Rule of the Big 3 38 1

Copying Data Structures Copying data is one of the most common operations in C++. Every time we write an assignment x = y ; we are copying data. As our data gets more complicated, so does copying. But, First... A slight diversion... 1 Destructors Destructors Destructors are used to clean up objects that are no longer in use. A destructor for a class C is a function named ~C This function takes no parameters The most common action within a destructor is deleting pointers CS333 2

Destructors are never Called Explicitly The compiler generates all calls to destructors implicitly when a variable goes out of scope, or when we delete a pointer. Implicit Destructor Call 1 If we write void foo ( int d, int c ) Money m (d, c ) ; for ( int i = 0 ; i < 100; ++ i ) Money mon2 = m;. the compiler generates void foo ( int d, int c ) Money m (d, c ) ; for ( int i = 0 ; i < 100; ++ i ) Money mon2 = m;. mon2.~money ( ) ; m.~money ( ) ; CS333 3

Implicit Destructor Call 2 If we write void foo ( int d, int c ) Money* m. = new Money (d, c ) ; delete m; the compiler generates void foo ( int d, int c ) Money* m. = new Money (d, c ) ; m >~Money ( ) ; free (m) ; A Typical Destructor We use destructors to clean up data owned by our structured types: class BidCollection int MaxSize ; int size ; Bid * elements ; / / array of bids public : BidCollection ( int MaxBids = 1000); ~BidCollection ( ) ;. CS333 4

Implementing the Destructor The destructor would be implemented as BidCollection : : ~ BidCollection ( ) delete [ ] elements ; Compiler-Provided Destructors If you don t provide a destructor for a class, the compiler generates one for you automatically. The automatically generated destructor simply invokes the destructors for any data member objects. If none of the members have programmer-supplied destructors, does nothing. A Compiler-Generated Destructor We have not declared or implemented a destructor for our Time class, #ifndef TIMES_H #define TIMES_H #include <iostream> /** * Times in this program are represented by three integers: H, M, & S, representing CS333 5

* the hours, minutes, and seconds, respecitvely. */ class Time public: // Create time objects Time(); // midnight Time (int h, int m, int s); // Access to attributes int gethours() const; int getminutes() const; int getseconds() const; // Calculations with time void add (Time delta); Time difference (Time fromtime); /** * Read a time (in the format HH:MM:SS) after skipping any * prior whitepace. */ void read (std::istream& in); /** * Print a time in the format HH:MM:SS (two digits each) */ void print (std::ostream& out) const; CS333 6

// Comparison operators bool operator== (const Time&) const; bool operator< (const Time&) const; private: // From here on is hidden int secondssincemidnight; ; inline std::ostream& operator<< (std::ostream& out, const Time& t) t.print(out); return out; inline bool operator!= (const Time& t1, const Time& t2) return!(t1 == t2); inline bool operator> (const Time& t1, const Time& t2) return t2 < t1; CS333 7

inline bool operator<= (const Time& t1, const Time& t2) return!(t1 > t2); inline bool operator>= (const Time& t1, const Time& t2) return!(t1 < t2); #endif // TIMES_H That s OK We have not declared a destructor for our Bid class #ifndef BIDS_H #define BIDS_H #include <iostream> #include <string> #include "time.h" #include "money.h" // CS333 8

// Bids Received During Auction // class Bid std::string biddername; Money amount; std::string itemname; Time bidplacedat; public: Bid (std::string bidder, double amt, std::string item, Time placedat); Bid(); // Access to attribute std::string getbidder() const return biddername; double getamount() const return amount; std::string getitem() const return itemname; Time gettimeplacedat() const return bidplacedat; // Print a bid void print (std::ostream& out) const; // Comparison operators bool operator== (const Bid&) const; bool operator< (const Bid&) const; CS333 9

; inline std::ostream& operator<< (std::ostream& out, const Bid& b) b.print(out); return out; #endif Again that s OK * Despite the fact that the strings may need cleanup. Trusting the Compiler-generated Destructor CS333 10

What would happen if we trusted the compiler-generated destructor for BidCollection? Compiler-generated destructors are wrong when... The compiler-generated destructor will leak memory when Your ADT has pointers among its data members, and Your ADT objects do not share those pointers with other objects. 2 Copy Constructors Copy Constructors The copy constructor for a class Foo is the constructor of the form: Foo ( const Foo& oldcopy ) ; CS333 11

2.1 Where Do We Use a Copy Constructor? Where Do We Use a Copy Constructor? The copy constructor gets used in 5 situations: 1. When you declare a new object as a copy of an old one: Time time2 ( time1 ) ; or Time time2 = time1 ; 2. When a function call passes a parameter by copy (i.e., the formal parameter does not have a &): void foo (Time b, int k ) ;. Time noon (12, 0, 0 ) ; foo (noon, 0 ) ; / / foo actually gets a copy of noon 3. When a function returns an object: Time foo ( int k ) ; Time t ( k, 0, 0 ) ;. return t ; 4. When explicitly invoked in another constructor s initialization list: Name (string gname, string sname) : givenname(gname), surname(sname) CS333 12

5. When an object is a data member of another class for which the compiler has generated its own copy constructor. 2.2 Compiler-Generated Copy Constructors Compiler-Generated Copy Constructors If we do not create a copy constructor for a class, the compiler generates one for us. copies each data member via their individual copy constructors. For primitive types (int, double, pointers, etc.), just copies the bits. 2.3 Example: Bid: Compiler-Generated Copy Constructor Example: Bid: Compiler-Generated Copy Constructor struct Bid std : : string biddername ; Money amount ; std : : s t r i n g itemname ; Time bidplacedat ; ; Bid does not provide a copy constructor, so the compiler generates one for us, just as if we had written: struct Bid std::string biddername; Money amount; std::string itemname; Time bidplacedat; CS333 13

Bid (const Bid&); ;. Bid::Bid (const Bid& b) : biddername(b.biddername), amount(b.amount), itemname(b.itemname), bidplacedat(b.bidplacedat) and that s probably just fine. 2.4 Example: BidCollection: Compiler-Generated Copy Constructor Example: BidCollection: Compiler-Generated Copy Constructor struct BidCollection int MaxSize ; int size ; Bid * elements ; / / array of bids / * * * Create a c o l l e c t i o n capable of holding the indicated number of bids * / BidCollection ( int MaxBids = 1000); ~BidCollection ( ) ; / * * * Read a l l bids from the indicated f i l e * / void readbids ( std : : s t r i n g filename ) ; ; BidCollection does not provide a copy constructor, so the compiler generates one for us, just as if we had written: CS333 14

struct BidCollection int MaxSize; int size; Bid* elements; // array of bids /** * Create a collection capable of holding the indicated number of bids */ BidCollection (int MaxBids = 1000); BidCollection (const BidCollection&); ;. BidCollection::BidCollection (const BidCollection& bc) : MaxSize(bc.MaxSize), size(bc.size), elements(bc.elements) which is not good at all! Example: BidCollection is hard to copy To see why, suppose we had some application code: BidCollection removeearly (BidCollection bc, Time t) for (int i = 0; i < x.size;) if (bc.elements[i].bidplacedat < t) removeelement (elements, size, i); else ++i; CS333 15

return bc;. BidCollection afternoonbids = removeearly (bids, Time(12,0,0)); Assume we start with this in bids. CS333 16

When removeearly is called, we get a copy of bids. BidCollection removeearly ( BidCollection bc, Time t ) for ( int i = 0 ; i < x. s i z e ; ) i f ( bc. elements [ i ]. bidplacedat < t ) removeelement ( elements, size, i ) ; else ++ i ; return bc ;. BidCollection afternoonbids = removeearly ( bids, Time ( 1 2, 0, 0 ) ) ; removeearly removes the first morning bid from bc. BidCollection removeearly ( BidCollection bc, Time t ) for ( int i = 0 ; i < x. s i z e ; ) i f ( bc. elements [ i ]. bidplacedat < t ) removeelement ( elements, size, i ) ; else ++ i ; return bc ;. BidCollection afternoonbids = removeearly ( bids, Time ( 1 2, 0, 0 ) ) ; CS333 17

Then removeearly removes the remaining morning bid from bc. BidCollection removeearly ( BidCollection bc, Time t ) for ( int i = 0 ; i < x. s i z e ; ) i f ( bc. elements [ i ]. bidplacedat < t ) removeelement ( elements, size, i ) ; else ++ i ; return bc ;. BidCollection afternoonbids = removeearly ( bids, Time ( 1 2, 0, 0 ) ) ; CS333 18

The return statement makes a copy of bc, which is stored in afternoonbids removeearly removes the remaining morning bid from bc. BidCollection removeearly ( BidCollection bc, Time t ). return bc ;. BidCollection afternoonbids = removeearly ( bids, Time ( 1 2, 0, 0 ) ) ; Trouble: bids is corrupted CS333 19

Note that we have corrupted the original collection, bids It thinks it has more (according to size) bids than are left in the array The bids that it has are now changed That s not the worst of it! When we exit removeearly, BidCollection removeearly ( BidCollection bc, Time t ) for ( int i = 0 ; i < x. s i z e ; ) i f ( bc. elements [ i ]. bidplacedat < t ) removeelement ( elements, size, i ) ; else ++ i ; return bc ; CS333 20

the destructor for BidCollection is called on bc BidCollection : : ~ BidCollection ( ) delete [ ] elements ; Taking us from this... What a Mess! CS333 21

... to this. Both collections have "dangling pointers" Avoiding this Problem We could Decide never to pass a BidCollection by copy, never return one from a function, never to create a new BidCollection as a copy of an old one We would have to remember this in all future applications or, write our own copy constructor that actually works Every BidCollection should have its own unique array CS333 22

2.5 Writing a BidCollection Copy Constructor Writing a BidCollection Copy Constructor BidCollection : : BidCollection ( const BidCollection& bc ) : MaxSize ( bc. MaxSize ), s i z e ( bc. s i z e ) elements = new Bid [ MaxSize ] ; for ( int i = 0 ; i < size ; ++ i ) elements [ i ] = bc. elements [ i ] ; Once More, With Feeling! With this copy constructor in place, things should go much more smoothly. CS333 23

When removeearly is called, we get a copy of bids. BidCollection removeearly (BidCollection bc, Time t) for (int i = 0; i < x.size;) if (bc.elements[i].bidplacedat < t) removeelement (elements, size, i); else ++i; return bc;. BidCollection afternoonbids = removeearly (bids, Time(12,0,0)); CS333 24

removeearly removes the first morning bid from bc. BidCollection removeearly ( BidCollection bc, Time t ) for ( int i = 0 ; i < x. s i z e ; ) i f ( bc. elements [ i ]. bidplacedat < t ) removeelement ( elements, size, i ) ; else ++ i ; return bc ;. BidCollection afternoonbids = removeearly ( bids, Time ( 1 2, 0, 0 ) ) ; CS333 25

Then removeearly removes the remaining morning bid from bc. BidCollection removeearly ( BidCollection bc, Time t ) for ( int i = 0 ; i < x. s i z e ; ) i f ( bc. elements [ i ]. bidplacedat < t ) removeelement ( elements, size, i ) ; else ++ i ; return bc ;. BidCollection afternoonbids = removeearly ( bids, Time ( 1 2, 0, 0 ) ) ; CS333 26

The return statement makes a copy of bc, which is stored in afternoonbids. removeearly removes the remaining morning bid from bc. BidCollection removeearly ( BidCollection bc, Time t ). return bc ;. BidCollection afternoonbids = removeearly ( bids, Time ( 1 2, 0, 0 ) ) ; Much Nicer CS333 27

The destructor for BidCollection is called on bc Both remaining collections are OK. 2.6 Shallow & Deep Copying If We Never Write Our Own If our data members do not have explicit copy constructors (and their data members do not have explicit copy constructors, and... ) then the compiler-provided copy constructor amounts to a bit-by-bit copy. CS333 28

Shallow vs Deep Copy Copy operations are distinguished by how they treat pointers: In a shallow copy, all pointers are copied. Leads to shared data on the heap. In a deep copy, objects pointed to are copied, then the new pointer set to the address of the copied object. Copied objects keep exclusive access to the things they point to. Shallow copy is wrong when... Your ADT has pointers among its data members, and You don t want to share the objects being pointed to. Compiler-generated copy constructors are wrong when... Your ADT has pointers among its data members, and You don t want to share the objects being pointed to. CS333 29

3 Assignment Assignment Copy constructors are not the only way we make copies of data. Even more common is the use of assignment: time2 = time1 ; Assignment is so common that it can be hard to imagine programming without it though in rare conditions we will do so E.g., you cannot assign istreams and ostreams * You cannot copy them by constructor either So the compiler will try to be helpful again 3.1 Compiler-Generated Assignment Ops Compiler-Generated Assignment Ops If you don t provide your own assignment operator for a class, the compiler generates one automatically. assigns each data member in turn. If none of the members have programmer-supplied assignment ops, then this is a shallow copy CS333 30

Example: BidCollection: Guess what happens Our BidCollection class has no assignment operator, so the code below uses the compiler-generated version. Suppose we had some application code: BidCollection bids;. BidCollection bc; Time t (12, 0, 0); bc = bids; for (int i = 0; i < x.size;) if (bc.elements[i].bidplacedat < t) removeelement (elements, size, i); else ++i; BidCollection bc; Time t (12, 0, 0); bc = bids; for (int i = 0; i < x.size;) if (bc.elements[i].bidplacedat < t) removeelement (elements, size, i); else ++i; CS333 31

Assume we start with this in bids. After the assignment, we have copied bids, bitby-bit, into bc. BidCollection bc; Time t (12, 0, 0); CS333 32

bc = bids; for (int i = 0; i < x.size;) if (bc.elements[i].bidplacedat < t) removeelement (elements, size, i); else ++i; We remove the first morning bid from bc. BidCollection bc; Time t (12, 0, 0); bc = bids; for (int i = 0; i < x.size;) if (bc.elements[i].bidplacedat < t) removeelement (elements, size, i); else CS333 33

++i; Then remove the remaining morning bid from bc. bids is corrupted CS333 34

Note that we have corrupted the original collection, bids It thinks it has more (according to size) bids than are left in the array The bids that it has are now changed Avoiding this Problem We have already seen that, for this class, we need to implement our own copy constructor: BidCollection : : BidCollection ( const BidCollection& bc ) : MaxSize ( bc. MaxSize ), s i z e ( bc. s i z e ) elements = new Bid [ MaxSize ] ; for ( int i = 0 ; i < size ; ++ i ) elements [ i ] = bc. elements [ i ] ; For all the same reasons, we will want to implement our own assignment operator. 3.2 Implementing Assignment Implementing Assignment CS333 35

BidCollection& BidCollection : : operator= ( const BidCollection& bc ) MaxSize = bc. MaxSize ; s i z e = bc. s i z e ; delete [ ] elements ; elements = new Bid [ MaxSize ] ; for ( int i = 0 ; i < size ; ++ i ) elements [ i ] = bc. elements [ i ] ; return * this ; Why return *this? By tradition in C++, assignments can be chained: a = b = c = 0 ; Works because compiler interprets this as a = (b = ( c = 0 ) ) ; Not unlike << Self-Assignment What would happen if we did bids = bids ; CS333 36

using this assignment operator: BidCollection& BidCollection : : operator= ( const BidCollection& bc ) MaxSize = bc. MaxSize ; s i z e = bc. s i z e ; delete [ ] elements ; elements = new Bid [ MaxSize ] ; for ( int i = 0 ; i < size ; ++ i ) elements [ i ] = bc. elements [ i ] ; return * this ; Would delete all the elements before copying them Self-Assignment Really? May seem an unlikely occurrence, but can often happen in a disguised form, e.g., during array processing, bidset [ i ] = bidset [ j ] ; What if i == j? Coping with Self-Assignment To allow for this possibility, most assignment operator functions check to see if the variable on the left (this) is at the same address as the variable on the right: CS333 37

BidCollection& BidCollection::operator= (const BidCollection& bc) if (this!= &bc) MaxSize = bc.maxsize; size = bc.size; delete [] elements; elements = new Bid[MaxSize]; for (int i = 0; i < size; ++i) elements[i] = bc.elements[i]; return *this; 4 The Rule of the Big 3 A Question of Trust When do we not trust the compiler-provided copy constructor? When do we not trust the compiler-provided assignment operator? When do we not trust the compiler-provided destructor? A Question of Trust When do we not trust the compiler-provided copy constructor? CS333 38

When we have pointers among our data members, and We don t want to share the data we are pointing to When do we not trust the compiler-provided assignment operator? When we have pointers among our data members, and We don t want to share the data we are pointing to When do we not trust the compiler-provided destructor? When we have pointers among our data members, and We don t want to share the data we are pointing to Notice a pattern? The Rule of the Big 3 The copy constructor, assignment operator, and destructor are known as the Big 3. The Rule of the Big 3 states: If you provide your own version of any one of the Big 3, you should provide your own version of all three. Providing the Big 3 The Bid ADT: auctionbig3/bids.h and auctionbig3/bids.cpp The Bidder ADT: auctionbig3/bidders.h and auctionbig3/bidders.cpp The Item ADT: auctionbig3/items.h and auctionbig3/items.cpp CS333 39

The Time ADT: auctionbig3/time.h and auctionbig3/time.cpp The BidCollection ADT: auctionbig3/bidcollection.h and auctionbig3/bidcollection.cpp The BidderCollection ADT: auctionbig3/biddercollection.h and auctionbig3/biddercollection.cpp The ItemCollection ADT: auctionbig3/itemcollection.h and auctionbig3/itemcollection.cpp CS333 40