290 likes | 395 Views
159.234 LECTURE 11. Constructors and destructors Copy constructor Textbook: p. 156-166, 183. Constructor. P oint :: P oint () : x(0), y(0){} P oint :: P oint ( int i , int j): x( i ), y(j) {} A default constructor may be created as a function having the same Class name that
E N D
159.234LECTURE 11 • Constructors and destructors • Copy constructor • Textbook: • p. 156-166, 183
Constructor • Point::Point() : x(0), y(0){} • Point::Point(inti, int j): x(i), y(j) {} • A default constructor may be created as a function having the same Class name that • does not have any argument, or • comes with arguments with default values set • Const and Reference data members can only be initialized using an initializer list • Constructor initializers are in fact the preferred way of setting values.
Constructors with Default Arguments It is possible to construct constructors with default arguments. Example: Default Constructor: Point::Point() : x(0), y(0){} Default Argument Constructor: Point::Point(int i=0,int j=0):x(i), y(j) {} However, the default argument constructor becomes a default constructor when called without any arguments. When both forms appear in a class, ambiguity arises when the following statement is issued: Point p; Initializer list is not always declared at the class interface (See ch_stack.cpp for an example) No arguments
Calling the Constructor Explicit Call Point p = Point(5, 10); Creates a Point object p and passes the values 5 and 10 to it Implicit Call Point p(5, 10); Short-hand method; looks better and easier to implement
What is wrong in the following code? #include <iostream> using namespace std; int main(){ int *p, *r; p = new int; *p=10; r = new int; *r=25; r = p; cout <<(*p)<<" "<<(*r); delete p; cout << (*r)<<endl; delete r; // will cause double delete error return 0; } Memory Leak.cpp
Destructor Each class has exactly one destructor When an object is destroyed - the object’s destructor is called. Destructors are used when the object contains pointers and new has been used to allocate memory to them. If we don’t free that memory before the object disappears, then the memory will never be freed - a memory leak.
Destructor • class str { • public: • str(void); • ~str(); • char *s; • }; • str::str(void) { • s = new char[128]; • } • str::~str() { • delete[] s; • } The destructor function has the same name as the class with a ~ at the front. Destructors do not have return values, and cannot have arguments – not even void.
Destructor Destructors are used to release any resources allocated by the object. The most common example is when the constructor uses new, and the destructor uses delete. Destructors are a "prepare to die" member function. They are often abbreviated "dtor". Constructors are “ctor”.
Destructor • Destructor: • called by the system for you when an object is destroyable (e.g. about to go out of scope) • has the same name as the class; • with a~at the front; • does not have return values; • cannot have arguments.
When are constructors/destructors called? Constructors and destructors are called automatically. The order in which they are called depends on the order in which execution enters and leaves the scope in which objects are instantiated and the type of storage for objects. General rule:destructor calls are made in the reverse order of the constructor calls.
class C { • public: • C(int); //constructor • ~C(); //destructor • private: • int data; • }; • C::C(int value){ • data = value; • cout<<“\nCtor called: "<< data; • } • C::~C(){ • cout<<“\nDtor called: "<< data; • }
void createFc(); C one(1); //global object int main(){ cout <<"Main starts here."<<endl; static C two(2); //local static object cout<<"After two(local static)in main."<<endl; createFc(); //function call } void createFc(){ cout <<endl<<" FC STARTS HERE. "<<endl; C ten(77); //local object cout<< "LAST IN FC. "<<endl<<endl; }
Output: • Ctor called: 1 • Main starts here. • Ctor called: 2 • After two (local static) in main. • FC STARTS HERE. • Ctor called: 77 • LAST IN FC. • Dtor called: 77 • Dtor called: 2 • Dtor called: 1 global Local static Local Constructor and Destructor Call.cpp
When are constructors/destructors called? Destructor called: For stack objects defined: Constructors called: Before any other function (including main) When main terminates, or exit is called In global scope When the object enters scope. When the object leaves scope Local objects Static local objects Once, when the object enters scope the first time. When main terminates, or exit is called
Problems when passing objects: Object as argument Objects can be passed as function arguments. class Str{ public: Str(){ s = new char[128]; assert(s!=0); //… } ~Str(){ delete[] s } void print(){ //...} private: char* s; }; void display( Str s); Passing Object Using Call by Value.cpp
Problems when passing objects: int main(){ Str a; a.print(); //... if (value > 100) {display(a);} a.print(); } void display( Str s){s.print();} Assume that the value stored in a was “aaaaaaaaaa” Output: Data is aaaaaaaaaa Data is aaaaaaaaaa Data is ¿?A ¿?A aa
Problem: The destructor is called when display(a)finishes; It damages the original object a. How to solve it? Use call by reference: voiddisplay(Str &s);so no copying is done OR 2. Write a copy constructorfor the class which does a proper (deep) copy Passing object using Call by Reference.cpp Copy Constructor.cpp
Copy Constructor If we pass an object as an argument to a function Str p; display(p); The object is copied to the called routine. The copy constructor of the class is called to perform the copy. When the class does not provide its copy constructor the copy constructor provided by the system is used, but this is not appropriate for classes with pointer data members! System copy constructor only does a shallow job!
Copy Constructor • The copy constructor has the form: • Str::Str(const Str &x) • The original object is referred to by x. Strhas to copy it into the new object. • Str::Str(const Str &x){ • s = new char[128]; • strcpy(s,x.s); • } • This performs a deep copy. • A new string is created in the object, and the original string copied into it.
Copy Constructor If we omit the copy constructor, or write our own one like this: str::str(const str &x) { s = x.s; } Then we get a shallow copy. s is set to be the same pointer as x.s - there is only one string, both objects point to it. When using a shallow copy, it is important to know how many objects refer to the same memory location. Only when the last object is destroyed can that memory be freed safely.
Copy Constructor The copy constructor is also called when a function returns a class, and when an object is initialised with another object. str s1; str s2(s1); str *sp = new str(s2);
When is a copy constructor called? SUMMARY • 1. When a copy of an object is required, such as in call-by-value. • Str p; • display(p); • 2. When returningan object by value from a function. • Point findMiddlePt ( Point p1,Point p2){ • Point temp ; • //---do something • return temp; • } • 3. When initializing an object to be a copy of another object of the same class. • Str x; • //...other statements here • Str y(x);//y declared and initialized with x • or • Str y = x;//y declared and initialized with x
Constructor for Conversion There is one final use for constructors – to convert between types. class point { public: point(inti=0, int j=0) : x(i),y(j) {} ... }; This point constructor allows us to create objects like: point a; //x,y defaults so a = (0,0) point b(3); //y defaults so b = (3,0) point c(2,3); //no defaults so c = (2,3)
Constructor for Conversion If in our code we write: a = 4; at first sight, this appears to be wrong, a is a point and 4 is an integer. However the compiler allows it, as the constructor can be used to do the conversion. The constructor tells the compiler how to create a point out of an integer.
Constructor for Conversion If we do not want the constructor to be used in this fashion, then we need to use the keyword explicit class point { public: explicit point(inti=0, int j=0) : x(i),y(j) {} ... }; See pr_char.cpp See ch_stack.cpp
Sample Program: ch_stack See ch_stack.cpp Str T h i s Initially, 99 99 .. .. .. .. 2 2 1 1 0 T 0 Top s Push • Increment Top • Put character into element • of stack pointed to by Top Top=-1 Max_len=100 Data members
#include <iostream> #include <cstring> #include <assert.h> using namespace std; void display( Str s); // prototype class Str{ public: Str(char c = ' '){ p = new char[MAXLEN]; assert(p!=0); p[0] = c; p[1] = '\0'; } ~Str(){ delete[] p; } Str( const Str &src ){ // copy constructor p = new char[MAXLEN]; // makes p point to another memory address assert( p != 0 ); strncpy( p, src.p, MAXLEN ); // do a deep copy of the string } void print(){ cout << "Contents:" << p << endl;} char* p; const static int MAXLEN = 128; }; void display( Str s){ // s is a partial (shallow) copy (has same internal p value) s.print(); // s is now freed up automaticaly - but this can damage (object a) } int main(){ Str a('A'); // a now in scope a.print(); int value = 101; cerr << "Debug line 1" << endl; if (value > 100){ display(a); // passes a copy of a } cerr << "Debug line 2" << endl; a.print(); cerr << "Debug line 3" << endl; return 0; } Example Output: Contents:A Debug line 1 Contents:A Debug line 2 Contents:A Debug line 3
Summary • A constructor constructs objects of its class type. This process may involve data members and allocating free store, using operator new. • A default constructor is a constructor requiring no arguments (initialising arrays). • A copy constructor is used to copy one value into another when: • a type variable is initialized by a type value; • a type value is passed as an argument to a function; • a type value is returned from a function. A destructor “releases” any resources allocated by the object, typically by using delete.
Next: Friend functions/classes Textbook: p.200-203