[go: up one dir, main page]

0% found this document useful (0 votes)
26 views29 pages

W4 C2 Copy Const Copy Assign

Module 14 focuses on programming in C++, specifically on object lifetime, copy constructors, and copy assignment operators. It covers concepts such as shallow and deep copy, self-copy, and the importance of initialization order in class data members. The module includes practical examples and comparisons to illustrate these concepts effectively.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
26 views29 pages

W4 C2 Copy Const Copy Assign

Module 14 focuses on programming in C++, specifically on object lifetime, copy constructors, and copy assignment operators. It covers concepts such as shallow and deep copy, self-copy, and the importance of initialization order in class data members. The module includes practical examples and comparisons to illustrate these concepts effectively.
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 29

Module 14

Intructors: Abir
Das and
Sourangshu
Bhattacharya
Module 14: Programming in C++
Obj. Lifetime Copy Constructor and Copy Assignment Operator
String
Date
Rect

Copy Constructor
Call by Value
Intructors: Abir Das and Sourangshu Bhattacharya
Signature
Free Copy & Pitfall
Department of Computer Science and Engineering
Assignment Op.
Indian Institute of Technology, Kharagpur
Copy Objects
Self-Copy
{abir, sourangshu}@cse.iitkgp.ac.in
Signature
Free Assignment

Comparison
Slides taken from NPTEL course on Programming in Modern C++
Class as Type
by Prof. Partha Pratim Das
Module Summary

CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 1


Module Objectives

Module 14

Intructors: Abir • More on Object Lifetime


Das and
Sourangshu
Bhattacharya
• Understand Copy Construction
Obj. Lifetime
• Understand Copy Assignment Operator
String
Date
• Understand Shallow and Deep Copy
Rect

Copy Constructor
Call by Value
Signature
Free Copy & Pitfall

Assignment Op.
Copy Objects
Self-Copy
Signature
Free Assignment

Comparison

Class as Type

Module Summary

CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 2


Module Outline

Module 14 1 Object Lifetime Examples


Intructors: Abir String
Das and
Sourangshu Date: Practice
Bhattacharya Rect: Practice
Obj. Lifetime 2 Copy Constructor
String
Date
Call by Value
Rect Signature
Copy Constructor
Free Copy Constructor and Pitfalls
Call by Value
Signature
3 Copy Assignment Operator
Free Copy & Pitfall Copy Objects
Assignment Op. Self-Copy
Copy Objects Signature
Self-Copy
Signature
Free Assignment Operator
Free Assignment
4 Comparison of Copy Constructor and Copy Assignment Operator
Comparison

Class as Type 5 Class as a Data-type


Module Summary
6 Module Summary
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 3
Program 14.01/02: Order of Initialization: Order of Data Members
#include <iostream> #include <iostream>
Module 14 using namespace std; using namespace std;
Intructors: Abir
int init_m1(int m) { // Func. to init m1_ int init_m1(int m) { // Func. to init m1_
Das and cout << "Init m1_: " << m << endl; cout << "Init m1_: " << m << endl;
Sourangshu return m; return m;
Bhattacharya
} }
int init_m2(int m) { // Func. to init m2_ int init_m2(int m) { // Func. to init m2_
Obj. Lifetime
cout << "Init m2_: " << m << endl; cout << "Init m2_: " << m << endl;
String
return m; return m;
Date
Rect
} }
class X { int m1_; // Initialize 1st class X { int m2_; // Order of data members swapped
Copy Constructor int m2_; // Initialize 2nd int m1_;
Call by Value
public: X(int m1, int m2) : public: X(int m1, int m2) :
Signature
m1_(init_m1(m1)), // Called 1st m1_(init_m1(m1)), // Called 2nd
Free Copy & Pitfall
m2_(init_m2(m2)) // Called 2nd m2_(init_m2(m2)) // Called 1st
Assignment Op. { cout << "Ctor: " << endl; } { cout << "Ctor: " << endl; }
Copy Objects ~X() { cout << "Dtor: " << endl; } }; ~X() { cout << "Dtor: " << endl; } };
Self-Copy
int main() { X a(2, 3); return 0; } int main() { X a(2, 3); return 0; }
Signature
----- -----
Free Assignment
Init m1_: 2 Init m2_: 3
Comparison Init m2_: 3 Init m1_: 2
Class as Type Ctor: Ctor:
Dtor: Dtor:
Module Summary
• Order of initialization does not depend on the order in the initialization list. It depends on the order of data members
in the definition
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 4
Program 14.03/04: A Simple String Class
C Style C++ Style
Module 14
#include <iostream> #include <iostream>
Intructors: Abir #include <cstring> #include <cstring>
Das and
Sourangshu
#include <cstdlib> #include <cstdlib>
Bhattacharya using namespace std; using namespace std;
struct String { char *str_; // Container class String { char *str_; // Container
Obj. Lifetime size_t len_; // Length size_t len_; // Length
String }; public: String(char *s) : str_(strdup(s)), // Uses malloc()
Date void print(const String& s) { len_(strlen(str_))
Rect cout << s.str_ << ": " { cout << "ctor: "; print(); }
Copy Constructor << s.len_ << endl; ~String() { cout << "dtor: "; print();
Call by Value } free(str_); // To match malloc() in strdup()
Signature int main() { String s; }
Free Copy & Pitfall void print() { cout << "(" << str_ << ": "
Assignment Op. // Init data members << len_ << ")" << endl; }
Copy Objects
s.str_ = strdup("Partha"); size_t len() { return len_; }
Self-Copy s.len_ = strlen(s.str_); };
Signature print(s); int main() { String s = "Partha"; // Ctor called
Free Assignment free(s.str); s.print();
Comparison
} }
----- -----
Class as Type ctor: (Partha: 6)
Partha: 6
Module Summary (Partha: 6)
dtor: (Partha: 6)
• Note the order of initialization between str and len . What if we swap them?
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 5
Program 14.05: A Simple String Class:
Fails for wrong order of data members
#include <iostream>
Module 14
#include <cstring>
Intructors: Abir #include <cstdlib>
Das and using namespace std;
Sourangshu
Bhattacharya
class String {
Obj. Lifetime size_t len_; // Swapped members cause garbage to be printed or program crash (unhandled exception)
String char *str_;
Date public:
Rect String(char *s) : str_(strdup(s)), len_(strlen(str_)) { cout << "ctor: "; print(); }
Copy Constructor
~String() { cout << "dtor: "; print(); free(str_); }
Call by Value
void print() { cout << "(" << str_ << ": " << len_ << ")" << endl; }
Signature
};
Free Copy & Pitfall int main() { String s = "Partha";
s.print();
Assignment Op.
}
Copy Objects
Self-Copy
----- // May produce garbage or crash
Signature
ctor: (Partha: 20)
Free Assignment (Partha: 20) // Garbage
dtor: (Partha: 20)
Comparison

Class as Type • len precedes str in list of data members


• len (strlen(str )) is executed before str (strdup(s))
Module Summary
• When strlen(str ) is called str is still uninitialized
• May causes the program to crash
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 6
Practice: Program 14.06: A Simple Date Class
#include <iostream>
Module 14
using namespace std;
Intructors: Abir
Das and char monthNames[][4]={ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
Sourangshu
Bhattacharya char dayNames[][10] ={ "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday" };
class Date {
Obj. Lifetime enum Month { Jan = 1, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec };
String enum Day { Mon, Tue, Wed, Thr, Fri, Sat, Sun };
Date typedef unsigned int UINT;
Rect UINT date_; Month month_; UINT year_;
Copy Constructor
public:
Call by Value
Date(UINT d, UINT m, UINT y) : date_(d), month_((Month)m), year_(y) { cout << "ctor: "; print(); }
Signature
~Date() { cout << "dtor: "; print(); }
Free Copy & Pitfall void print() { cout << date_ << "/" << monthNames[month_ - 1] << "/" << year_ << endl; }
bool validDate() { /* Check validity */ return true; } // Not implemented
Assignment Op.
Day day() { /* Compute day from date using time.h */ return Mon; } // Not implemented
Copy Objects
Self-Copy
};
Signature
int main() {
Free Assignment Date d(30, 7, 1961);
d.print();
Comparison
}
Class as Type -----
Module Summary ctor: 30/Jul/1961
30/Jul/1961
dtor: 30/Jul/1961
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 7
Practice: Program 14.07: Point and Rect Classes:
Lifetime of Data Members or Embedded Objects
Module 14
#include <iostream> class Rect { Point TL_; Point BR_; public:
using namespace std; Rect(int tlx, int tly, int brx, int bry):
Intructors: Abir class Point { int x_; int y_; public: TL_(tlx, tly), BR_(brx, bry)
Das and
Sourangshu
Point(int x, int y): { cout << "Rect ctor: ";
Bhattacharya x_(x), y_(y) print(); cout << endl; }
{ cout << "Point ctor: "; ~Rect() { cout << "Rect dtor: ";
Obj. Lifetime print(); cout << endl; } print(); cout << endl; }
String ~Point() { cout << "Point dtor: "; void print() { cout << "["; TL_.print();
Date print(); cout << endl; } cout << " "; BR_.print(); cout << "]"; }
Rect void print() { cout << "(" << x_ << ", " };
Copy Constructor
<< y_ << ")"; } -----
Call by Value
}; Point ctor: (0, 2)
Signature Point ctor: (5, 7)
Free Copy & Pitfall int main() { Rect ctor: [(0, 2) (5, 7)]
Rect r (0, 2, 5, 7);
Assignment Op.
Copy Objects
[(0, 2) (5, 7)]
Self-Copy
cout << endl; r.print(); cout << endl;
Signature Rect dtor: [(0, 2) (5, 7)]
Free Assignment cout << endl; Point dtor: (5, 7)
} Point dtor: (0, 2)
Comparison

Class as Type • Attempt is to construct a Rect object


Module Summary • That, in turn, needs constructions of Point data members (or embedded objects) – TL and BR respectively
• Destruction, initiated at the end of scope of destructor’s body, naturally follows a reverse order

CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 8


Copy Constructor

Module 14

Intructors: Abir • We know:


Das and
Sourangshu
Bhattacharya
Complex c1(4.2, 5.9);
invokes
Obj. Lifetime
String Constructor Complex::Complex(double, double);
Date
Rect • Which constructor is invoked for?
Copy Constructor
Call by Value
Complex c2(c1);
Signature
Free Copy & Pitfall

Assignment Op. Or for?


Copy Objects
Self-Copy Complex c2 = c1;
Signature
Free Assignment • It is the Copy Constructor that takes an object of the same type and constructs a
Comparison copy:
Class as Type
Complex::Complex(const Complex &);
Module Summary

CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 9


Program 14.08: Complex: Copy Constructor
#include <iostream>
Module 14
#include <cmath> -----
Intructors: Abir using namespace std; Complex ctor: |4.2+j5.3| = 6.7624 // Ctor: c1
Das and class Complex { double re_, im_; public: Complex copy ctor: |4.2+j5.3| = 6.7624 // CCtor: c2 of c1
Sourangshu
Bhattacharya // Constructor Complex copy ctor: |4.2+j5.3| = 6.7624 // CCtor: c3 of c2
Complex(double re, double im): |4.2+j5.3| = 6.7624 // c1
Obj. Lifetime re_(re), im_(im) |4.2+j5.3| = 6.7624 // c2
String { cout << "Complex ctor: "; print(); } |4.2+j5.3| = 6.7624 // c3
Date // Copy Constructor Complex dtor: |4.2+j5.3| = 6.7624 // Dtor: c3
Rect Complex(const Complex& c): Complex dtor: |4.2+j5.3| = 6.7624 // Dtor: c2
Copy Constructor
re_(c.re_), im_(c.im_) Complex dtor: |4.2+j5.3| = 6.7624 // Dtor: c1
Call by Value
{ cout << "Complex copy ctor: "; print(); }
Signature
// Destructor
Free Copy & Pitfall ~Complex()
{ cout << "Complex dtor: "; print(); }
Assignment Op.
double norm() { return sqrt(re_*re_ + im_*im_); }
Copy Objects
Self-Copy
void print() { cout << "|" << re_ << "+j" << im_ << "| = " << norm() << endl; }
Signature
};
Free Assignment int main() {
Complex c1(4.2, 5.3), // Constructor - Complex(double, double)
Comparison
c2(c1), // Copy Constructor - Complex(const Complex&)
Class as Type c3 = c2; // Copy Constructor - Complex(const Complex&)
Module Summary
c1.print(); c2.print(); c3.print();
}
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 10
Why do we need Copy Constructor?

Module 14

Intructors: Abir • Consider the function call mechanisms in C++:


Das and
Sourangshu
Bhattacharya
◦ Call-by-reference: Set a reference to the actual parameter as a formal parameter.
Both the formal parameter and the actual parameter share the same location
Obj. Lifetime
String
(object). No copy is needed
Date ◦ Return-by-reference: Set a reference to the computed value as a return value. Both
Rect
the computed value and the return value share the same location (object). No copy
Copy Constructor
Call by Value is needed
Signature
Free Copy & Pitfall
◦ Call-by-value: Make a copy or clone of the actual parameter as a formal parameter.
Assignment Op.
This needs a Copy Constructor
Copy Objects ◦ Return-by-value: Make a copy or clone of the computed value as a return value.
Self-Copy
Signature This needs a Copy Constructor
Free Assignment

Comparison
• Copy Constructor is needed for initializing the data members of a UDT from an
Class as Type
existing value
Module Summary

CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 11


Program 14.09: Complex: Call by value
#include <iostream>
Module 14
#include <cmath>
Intructors: Abir using namespace std;
Das and class Complex { double re_, im_; public:
Sourangshu
Bhattacharya Complex(double re, double im): re_(re), im_(im) // Constructor
{ cout << "ctor: "; print(); }
Obj. Lifetime Complex(const Complex& c): re_(c.re_), im_(c.im_) // Copy Constructor
String { cout << "copy ctor: "; print(); }
Date ~Complex() { cout << "dtor: "; print(); }
Rect double norm() { return sqrt(re_*re_ + im_*im_); }
Copy Constructor
void print() { cout << "|" << re_ << "+j" << im_ << "| = " << norm() << endl; }
Call by Value
};
Signature
void Display(Complex c_param) { // Call by value
Free Copy & Pitfall cout << "Display: "; c_param.print();
}
Assignment Op.
int main() { Complex c(4.2, 5.3); // Constructor - Complex(double, double)
Copy Objects
Self-Copy
Signature
Display(c); // Copy Constructor called to copy c to c_param
Free Assignment }
-----
Comparison
ctor: |4.2+j5.3| = 6.7624 // Ctor of c in main()
Class as Type copy ctor: |4.2+j5.3| = 6.7624 // Ctor c_param as copy of c, call Display()
Module Summary Display: |4.2+j5.3| = 6.7624 // c_param
dtor: |4.2+j5.3| = 6.7624 // Dtor c_param on exit from Display()
dtor: |4.2+j5.3| = 6.7624 // Dtor of c on exit from main()
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 12
Signature of Copy Constructors

Module 14

Intructors: Abir
• Signature of a Copy Constructor can be one of:
Das and
Sourangshu MyClass(const MyClass& other); // Common
Bhattacharya
// Source cannot be changed
MyClass(MyClass& other); // Occasional
Obj. Lifetime
// Source needs to change. Like in smart pointers
String
MyClass(volatile const MyClass& other); // Rare
Date
Rect
MyClass(volatile MyClass& other); // Rare
Copy Constructor
Call by Value
• None of the following are copy constructors, though they can copy:
Signature
Free Copy & Pitfall MyClass(MyClass* other);
Assignment Op. MyClass(const MyClass* other);
Copy Objects
Self-Copy
Signature
• Why the parameter to a copy constructor must be passed as Call-by-Reference?
Free Assignment
MyClass(MyClass other);
Comparison

Class as Type

Module Summary
The above is an infinite recursion of copy calls as the call to copy constructor itself
needs to make copy for the Call-by-Value mechanism
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 13
Free Copy Constructor

Module 14
• If no copy constructor is provided by the user, the compiler supplies a free one
Intructors: Abir
• Free copy constructor cannot initialize the object to proper values. It performs Shallow Copy
Das and • Shallow Copy aka bit-wise copy, field-by-field copy, field-for-field copy, or field copy
Sourangshu
Bhattacharya ◦ An object is created by simply copying the data of all variables of the original object
Obj. Lifetime
◦ Works well if none of the variables of the object are defined in heap / free store
String ◦ For dynamically created variables, the copied object refers to the same memory location
Date
Rect
◦ Creates ambiguity (changing one changes the copy) and run-time errors (dangling pointer)
Copy Constructor • Deep Copy or its variants Lazy Copy and Copy-on-Write
Call by Value
Signature
◦ An object is created by copying data of all variables except the ones on heap
Free Copy & Pitfall ◦ Allocates similar memory resources with the same value to the object
Assignment Op. ◦ Need to explicitly define the copy constructor and assign dynamic memory as required
Copy Objects
Self-Copy
◦ Required to dynamically allocate memory to the variables in the other constructors
Signature
Free Assignment

Comparison

Class as Type

Module Summary

CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 14


Pitfalls of Bit-wise Copy: Shallow Copy

Module 14 • Consider a class:


Intructors: Abir
class A { int i_; // Non-pointer data member
Das and int* p_; // Pointer data member
Sourangshu public:
Bhattacharya
A(int i, int j) : i_(i), p_(new int(j)) { } // Init. with pointer to dynamically created object
~A() { cout << "Destruct " << this << ": "; // Object identity
Obj. Lifetime
cout << "i_ = " << i_ << " p_ = " << p_ << " *p = " << *p_ << endl; // Object state
String
delete p_; // Release resource
Date
}
Rect
};
Copy Constructor
Call by Value • As no copy constructor is provided, the implicit copy constructor does a bit-wise copy. So
Signature
Free Copy & Pitfall
when an A object is copied, p is copied and continues to point to the same dynamic int:
int main() { A a1(2, 3); A a2(a1); // Construct a2 as a copy of a1. Done by bit-wise copy
Assignment Op.
cout << "&a1 = " << &a1 << " &a2 = " << &a2 << endl;
Copy Objects
Self-Copy
}
Signature
Free Assignment
• The output is wrong, as a1.p = a2.p points to the same int location. Once a2 is destructed,
Comparison
a2.p is released, and a1.p becomes dangling. The program may print garbage or crash:
&a1 = 008FF838 &a2 = 008FF828 // Identities of objects
Class as Type
Destruct 008FF828: i_ = 2 p_ = 00C15440 *p = 3 // Dtor of a2. Note that a2.p_ = a1.p_
Module Summary Destruct 008FF838: i_ = 2 p_ = 00C15440 *p = -17891602 // Dtor of a1. a1.p_=a2.p_ points to garbage

• The bit-wise copy of members is known as Shallow Copy


CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 15
Pitfalls of Bit-wise Copy: Deep Copy

Module 14 • Now suppose we provide a user-defined copy constructor:


Intructors: Abir
class A { int i_; // Non-pointer data member
Das and int* p_; // Pointer data member
Sourangshu public:
Bhattacharya
A(int i, int j) : i_(i), p_(new int(j)) { } // Init. with pointer to dynamically created object
A(const A& a) : i_(a.i_), // Copy Constructor
Obj. Lifetime
p_(new int(*a.p_)) { } // Allocation done and value copied - Deep Copy
String
~A() { cout << "Destruct " << this << ": "; // Object identity
Date
cout << "i_ = " << i_ << " p_ = " << p_ << " *p = " << *p_ << endl; // Object state
Rect
delete p_; // Release resource
Copy Constructor }
Call by Value
};
Signature
Free Copy & Pitfall • The output now is correct, as a1.p ̸= a2.p points to the different int locations with the
Assignment Op. values *a1.p = *a2.p properly copied:
Copy Objects
&a1 = 00B8F9E0 &a2 = 00B8F9D0 // Identities of objects
Self-Copy
Signature
Destruct 00B8F9D0: i_ = 2 p_ = 00C95480 *p = 3 // Dtor of a2. a2.p_ is different from a1.p_
Free Assignment
Destruct 00B8F9E0: i_ = 2 p_ = 00C95440 *p = 3 // Dtor of a1. Works correctly!
Comparison • This is known as Deep Copy where every member is copied properly. Note that:
Class as Type ◦ In every class, provide copy constructor to adopt to deep copy which is always safe
Module Summary ◦ Naturally, shallow copy is cheaper than deep copy.
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 16
Practice: Program 14.10: Complex: Free Copy Constructor
#include <iostream>
Module 14
#include <cmath>
Intructors: Abir using namespace std;
Das and class Complex { double re_, im_; public:
Sourangshu
Bhattacharya Complex(double re, double im) : re_(re), im_(im) { cout << "ctor: "; print(); } // Ctor
// Complex(const Complex& c) : re_(c.re_), im_(c.im_) { cout<<"copy ctor: "; print(); } // CCtor: Free only
Obj. Lifetime ~Complex() { cout << "dtor: "; print(); } // Dtor
String double norm() { return sqrt(re_*re_ + im_*im_); }
Date void print() { cout << "|" << re_ << "+j" << im_ << "| = " << norm() << endl; }
Rect };
Copy Constructor
void Display(Complex c_param) { cout << "Display: "; c_param.print(); }
Call by Value
int main() { Complex c(4.2, 5.3); // Constructor - Complex(double, double)
Signature
Display(c); // Free Copy Constructor called to copy c to c_param
Free Copy & Pitfall }
User-defined CCtor Free CCtor
Assignment Op.
ctor: |4.2+j5.3| = 6.7624 ctor: |4.2+j5.3| = 6.7624
Copy Objects
copy ctor: |4.2+j5.3| = 6.7624 No message from free CCtor
Self-Copy
Display: |4.2+j5.3| = 6.7624 Display: |4.2+j5.3| = 6.7624
Signature
Free Assignment
dtor: |4.2+j5.3| = 6.7624 dtor: |4.2+j5.3| = 6.7624
dtor: |4.2+j5.3| = 6.7624 dtor: |4.2+j5.3| = 6.7624
Comparison

Class as Type • User has provided no copy constructor


• Compiler provides free copy constructor
Module Summary
• Compiler-provided copy constructor performs bit-wise copy - hence there is no message
• Correct in this case as members are of built-in type and there is no dynamically allocated data
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 17
Practice: Program 14.11: String: User-defined Copy Constructor
#include <iostream>
Module 14
#include <cstdlib>
Intructors: Abir #include <cstring>
Das and using namespace std;
Sourangshu
Bhattacharya class String { public: char *str_; size_t len_;
String(char *s) : str_(strdup(s)), len_(strlen(str_)) { } // Ctor
Obj. Lifetime String(const String& s) : str_(strdup(s.str_)), len_(s.len_) { } // CCtor: User provided
String ~String() { free(str_); } // Dtor
Date void print() { cout << "(" << str_ << ": " << len_ << ")" << endl; }
Rect };
Copy Constructor
void strToUpper(String a) { // Make the string uppercase
Call by Value
for (int i = 0; i < a.len_; ++i) { a.str_[i] = toupper(a.str_[i]); }
Signature
cout << "strToUpper: "; a.print();
Free Copy & Pitfall } // a.~String() is invoked releasing a.str_. s.str_ remains intact
int main() { String s = "Partha"; s.print(); strToUpper(s); s.print(); }
Assignment Op.
---
Copy Objects
Self-Copy
(Partha: 6)
Signature
strToUpper: (PARTHA: 6)
Free Assignment (Partha: 6)
Comparison • User has provided copy constructor. So Compiler does not provide free copy constructor
Class as Type • When actual parameter s is copied to formal parameter a, space is allocated for a.str and then it is copied from
s.str . On exit from strToUpper, a is destructed and a.str is deallocated. But in main, s remains intact and access
Module Summary
to s.str is valid.
• Deep Copy: While copying the object, the pointed object is copied in a fresh allocation. This is safe
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 18
Practice: Program 14.12: String: Free Copy Constructor
#include <iostream>
Module 14 #include <cstring>
Intructors: Abir
#include <cstdlib>
Das and using namespace std;
Sourangshu class String { public: char *str_; size_t len_;
Bhattacharya
String(char *s) : str_(strdup(s)), len_(strlen(str_)) { } // Ctor
// String(const String& s) : str_(strdup(s.str_)), len_(s.len_) { } // CCtor: Free only
Obj. Lifetime
~String() { free(str_); } // Dtor
String
void print() { cout << "(" << str_ << ": " << len_ << ")" << endl; }
Date
Rect
};
void strToUpper(String a) { // Make the string uppercase
Copy Constructor for (int i = 0; i < a.len_; ++i) { a.str_[i] = toupper(a.str_[i]); } cout<<"strToUpper: "; a.print();
Call by Value
} // a.~String() is invoked releasing a.str_ and invalidating s.str_ = a.str_
Signature
int main() { String s = "Partha"; s.print(); strToUpper(s); s.print(); } // Last print fails
Free Copy & Pitfall

Assignment Op. User-defined CCtor Free CCtor


Copy Objects (Partha: 6) (Partha: 6)
Self-Copy strToUpper: (PARTHA: 6) strToUpper: (PARTHA: 6)
Signature (Partha: 6) (?????????????????????????????: 6)
Free Assignment
• User has provided no copy constructor. Compiler provides free copy constructor
Comparison
• Free copy constructor performs bit-copy - hence no allocation is done for str when actual parameter s is copied to
Class as Type formal parameter a. s.str is merely copied to a.str and both continue to point to the same memory. On exit from
Module Summary strToUpper, a is destructed and a.str is deallocated. Hence in main access to s.str is dangling. Program prints
garbage and / or crashes
• Shallow Copy: With bit-copy, only the pointer is copied - not the pointed object. This is risky
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 19
Copy Assignment Operator

Module 14

Intructors: Abir • We can copy an existing object to another existing object as


Das and
Sourangshu
Bhattacharya
Complex c1 = (4.2, 5.9), c2(5.1, 6.3);

Obj. Lifetime
String
c2 = c1; // c1 becomes { 4.2, 5.9 }
Date
Rect

Copy Constructor This is like normal assignment of built-in types and overwrites the old value with the
Call by Value
Signature
new value
Free Copy & Pitfall
• It is the Copy Assignment that takes an object of the same type and overwrites into
Assignment Op.
Copy Objects an existing one, and returns that object:
Self-Copy
Signature Complex::Complex& operator= (const Complex &);
Free Assignment

Comparison

Class as Type

Module Summary

CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 20


Program 14.13: Complex: Copy Assignment
#include <iostream>
Module 14 #include <cmath>
Intructors: Abir
using namespace std;
Das and class Complex { double re_, im_; public:
Sourangshu Complex(double re, double im) : re_(re), im_(im) { cout << "ctor: "; print(); } // Ctor
Bhattacharya
Complex(const Complex& c) : re_(c.re_), im_(c.im_) { cout << "cctor: "; print(); } // CCtor
~Complex() { cout << "dtor: "; print(); } // Dtor
Obj. Lifetime
Complex& operator=(const Complex& c) // Copy Assignment Operator
String
{ re_ = c.re_; im_ = c.im_; cout << "copy: "; print(); return *this; } // Return *this for chaining
Date
Rect
double norm() { return sqrt(re_*re_ + im_*im_); }
void print() { cout << "|" << re_ << "+j" << im_ << "| = " << norm() << endl; } }; // Class Complex
Copy Constructor int main() { Complex c1(4.2, 5.3), c2(7.9, 8.5); Complex c3(c2); // c3 Copy Constructed from c2
Call by Value
c1.print(); c2.print(); c3.print();
Signature
c2 = c1; c2.print(); // Copy Assignment Operator
Free Copy & Pitfall
c1 = c2 = c3; c1.print(); c2.print(); c3.print(); // Copy Assignment Chain
Assignment Op. }
Copy Objects ctor: |4.2+j5.3| = 6.7624 // c1 - ctor copy: |7.9+j8.5| = 11.6043 // c2 <- c3
Self-Copy ctor: |7.9+j8.5| = 11.6043 // c2 - ctor copy: |7.9+j8.5| = 11.6043 // c1 <- c2
Signature cctor: |7.9+j8.5| = 11.6043 // c3 - ctor |7.9+j8.5| = 11.6043 // c1
Free Assignment
|4.2+j5.3| = 6.7624 // c1 |7.9+j8.5| = 11.6043 // c2
Comparison |7.9+j8.5| = 11.6043 // c2 |7.9+j8.5| = 11.6043 // c3
Class as Type
|7.9+j8.5| = 11.6043 // c3 dtor: |7.9+j8.5| = 11.6043 // c3 - dtor
copy: |4.2+j5.3| = 6.7624 // c2 <- c1 dtor: |7.9+j8.5| = 11.6043 // c2 - dtor
Module Summary |4.2+j5.3| = 6.7624 // c2 dtor: |7.9+j8.5| = 11.6043 // c1 - dtor
• Copy assignment operator should return the object to make chain assignments possible
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 21
Program 14.14: String: Copy Assignment
#include <iostream>
Module 14
#include <cstring>
Intructors: Abir #include <cstdlib>
Das and using namespace std;
Sourangshu
Bhattacharya class String { public: char *str_; size_t len_;
String(char *s) : str_(strdup(s)), len_(strlen(str_)) { } // Ctor
Obj. Lifetime String(const String& s) : str_(strdup(s.str_)), len_(s.len_) { } // CCtor
String ~String() { free(str_); } // Dtor
Date String& operator=(const String& s) { // Copy Assignment Operator
Rect free(str_); // Release existing memory
Copy Constructor
str_ = strdup(s.str_); // Perform deep copy
Call by Value
len_ = s.len_; // Copy data member of built-in type
Signature
return *this; // Return object for chain assignment
Free Copy & Pitfall }
void print() { cout << "(" << str_ << ": " << len_ << ")" << endl; }
Assignment Op.
};
Copy Objects
Self-Copy
int main() { String s1 = "Football", s2 = "Cricket"; s1.print(); s2.print(); s2 = s1; s2.print(); }
Signature
---
Free Assignment (Football: 8)
(Cricket: 7)
Comparison
(Football: 8)
Class as Type • In copy assignment operator, str = s.str should not be done for two reasons:
1) Resource held by str will leak
Module Summary
2) Shallow copy will result with its related issues
• What happens if a self-copy s1 = s1 is done?
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 22
Program 14.15: String: Self Copy
#include <iostream>
Module 14
#include <cstring>
Intructors: Abir #include <cstdlib>
Das and using namespace std;
Sourangshu
Bhattacharya class String { public: char *str_; size_t len_;
String(char *s) : str_(strdup(s)), len_(strlen(str_)) { } // Ctor
Obj. Lifetime String(const String& s) : str_(strdup(s.str_)), len_(s.len_) { } // CCtor
String ~String() { free(str_); } // Dtor
Date String& operator=(const String& s) { // Copy Assignment Operator
Rect free(str_); // Release existing memory
str_ = strdup(s.str_); // Perform deep copy
Copy Constructor • For self-copy
Call by Value
len_ = s.len_; // Copy data member of built-in type
Signature
return *this; // Return object for chain assignment
Free Copy & Pitfall }
void print() { cout << "(" << str_ << ": " << len_ << ")" << endl; }
Assignment Op.
};
Copy Objects
Self-Copy
int main() { String s1 = "Football", s2 = "Cricket"; s1.print(); s2.print(); s1 = s1; s1.print(); }
Signature
---
Free Assignment (Football: 8)
(Cricket: 7)
Comparison
(????????: 8) // Garbage is printed. May crash too
Class as Type
• Hence, free(str ) first releases the memory, and then strdup(s.str ) tries to copy from released memory
Module Summary
• This may crash or produce garbage values
• Self-copy must be detected and guarded
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 23
Program 14.16: String: Self Copy: Safe
#include <iostream>
Module 14
#include <cstring>
Intructors: Abir #include <cstdlib>
Das and using namespace std;
Sourangshu
Bhattacharya class String { public: char *str_; size_t len_;
String(char *s) : str_(strdup(s)), len_(strlen(str_)) { } // Ctor
Obj. Lifetime String(const String& s) : str_(strdup(s.str_)), len_(s.len_) { } // CCtor
String ~String() { free(str_); } // Dtor
Date String& operator=(const String& s) { // Copy Assignment Operator
Rect if (this != &s) { // Check if the source and destination are same
Copy Constructor
free(str_);
str_ = strdup(s.str_);
Call by Value • Check for se
Signature
len_ = s.len_;
Free Copy & Pitfall }
return *this;
Assignment Op.
}
Copy Objects
Self-Copy
void print() { cout << "(" << str_ << ": " << len_ << ")" << endl; }
Signature
};
Free Assignment int main() { String s1 = "Football", s2 = "Cricket"; s1.print(); s2.print(); s1 = s1; s1.print(); }
---
Comparison
(Football: 8)
Class as Type (Cricket: 7)
Module Summary (Football: 8)
• In case of self-copy, do nothing
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 24
Signature and Body of Copy Assignment Operator

Module 14 • For class MyClass, typical copy assignment operator will be:
Intructors: Abir MyClass& operator=(const MyClass& s) {
Das and
Sourangshu if (this != &s) { // Check if the source and destination are same
Bhattacharya // Release resources held by *this
// Copy members of s to members of *this
Obj. Lifetime }
String return *this; // Return object for chain assignment
Date }
Rect

Copy Constructor • Signature of a Copy Assignment Operator can be one of:


Call by Value
Signature MyClass& operator=(const MyClass& rhs); // Common. No change in Source
Free Copy & Pitfall
MyClass& operator=(MyClass& rhs); // Occasional. Change in Source
Assignment Op.
Copy Objects • The following Copy Assignment Operators are occasionally used:
Self-Copy
Signature
MyClass& operator=(MyClass rhs);
Free Assignment
const MyClass& operator=(const MyClass& rhs);
Comparison const MyClass& operator=(MyClass& rhs);
Class as Type const MyClass& operator=(MyClass rhs);
MyClass operator=(const MyClass& rhs);
Module Summary
MyClass operator=(MyClass& rhs);
MyClass operator=(MyClass rhs);
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 25
Free Assignment Operator

Module 14

Intructors: Abir • If no copy assignment operator is provided/overloaded by the user, the compiler
Das and
Sourangshu supplies a free one
Bhattacharya
• Free copy assignment operator cannot copy the object with proper values. It performs
Obj. Lifetime
String
Shallow Copy
Date
Rect
• In every class, provide copy assignment operator to adopt to deep copy which is always
Copy Constructor safe
Call by Value
Signature
Free Copy & Pitfall

Assignment Op.
Copy Objects
Self-Copy
Signature
Free Assignment

Comparison

Class as Type

Module Summary

CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 26


Comparison of Copy Constructor and Copy Assignment Operator

Module 14
Copy Constructor Copy Assignment Operator
Intructors: Abir
Das and
Sourangshu
Bhattacharya • An overloaded constructor • An operator overloading
Obj. Lifetime • Initializes a new object with an existing • Assigns the value of one existing object
String
Date
object to another existing object
Rect • Used when a new object is created with • Used when we want to assign existing
Copy Constructor some existing object object to another object
Call by Value
Signature • Needed to support call-by-value and
Free Copy & Pitfall
return-by-value
Assignment Op.
Copy Objects
• Newly created object use new memory • Memory location of destination object
Self-Copy location is reused with pointer variables being re-
Signature
Free Assignment leased and reallocated
Comparison • Care is needed for self-copy
Class as Type • If not defined in the class, the compiler • If not overloaded, the compiler provides
Module Summary provides one with bitwise copy one with bitwise copy
CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 27
Class as a Data-type

Module 14 • We add the copy construction and assignment to a class being a composite data type in C++
Intructors: Abir
Das and
Sourangshu // declare i to be of int type // declare c to be of Complex type
Bhattacharya int i; Complex c;

Obj. Lifetime // initialise i // initialise the real and imaginary components of c


String int i = 5; Complex c = (4, 5); // Ctor
Date
int j = i; Complex c1 = c; // CCtor
Rect
int k(j); Complex c2(c1); // CCtor
Copy Constructor
Call by Value // print i // print the real and imaginary components of c
Signature cout << i; cout << c.re << c.im;
Free Copy & Pitfall OR c.print(); // Method Complex::print() defined for printing
Assignment Op. OR cout << c; // operator<<() overloaded for printing
Copy Objects
Self-Copy // add two ints // add two Complex objects
Signature int i = 5, j = 6; Complex c1 = (4, 5), c2 = (4, 6);
Free Assignment i+j; c1.add(c2); // Method Complex::add() defined to add
Comparison OR c1+c2; // operator+() overloaded to add
Class as Type // copy value of i to j // copy value of one Complex object to another
Module Summary int i = 5, j; Complex c1 = (4, 5), c2 = (4, 6);
j = i; c2 = c1; // c2.re <- c1.re and c2.im <- c1.im by copy assignment

CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 28


Module Summary

Module 14

Intructors: Abir • Copy Constructors


Das and
Sourangshu
Bhattacharya
◦ A new object is created
◦ The new object is initialized with the value of data members of another object
Obj. Lifetime
String • Copy Assignment Operator
Date
Rect
◦ An object is already existing (and initialized)
Copy Constructor ◦ The members of the existing object are replaced by values of data members of
Call by Value
Signature
another object
Free Copy & Pitfall ◦ Care is needed for self-copy
Assignment Op.
Copy Objects
• Deep and Shallow Copy for Pointer Members
Self-Copy
Signature
◦ Deep copy allocates new space for the contents and copies the pointed data
Free Assignment ◦ Shallow copy merely copies the pointer value – hence, the new copy and the original
Comparison
pointer continue to point to the same data
Class as Type

Module Summary

CS20202: Software Engineering Intructors: Abir Das and Sourangshu Bhattacharya 29

You might also like