The Practice of Programming, CSIE@NTNU, Fall, 2009
Construction, Destruction,and Assignment
Instructor: Tsung-Che [email protected]
Department of Computer Science and Information EngineeringNational Taiwan Normal University
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2009
Review of std::string
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2009
Review of std::string
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 20094
Warm-up Exercise
Define a class CPet Data members: name_, level_; Default values of name_ and level_ are “lucky”and 1,
respectively. Users can pass name and level when constructing a CPet
object.
Define a class CPlayer Data members: id_, name_, level_, pet_; id_ is a constant and must be provided when constructing aCPlayer object.
Default values of name_ and level_ are “player”and 1,respectively.
Users can pass player’s name, player’s level, pet’s name,and pet’s level when constructing a CPlayer object.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 20095
Warm-up Exercise
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 20096
Warm-up Exercise
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 20097
Warm-up Exercise
1 [Player] (1) with pet [Lucky] (1)2 [Jay] (1) with pet [Lucky] (1)3 [NTNU] (100) with pet [Lucky] (1)4 [CSIE] (1) with pet [Piggy] (1)5 [tcchiang] (10) with pet [dragon] (100)
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 20098
Outline
Review of constructorsReview of destructorsRelated rules & guidelines
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2009
Constructor
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200910
Purpose of Constructors
If a class does not have a constructor, initializing itsobjects is a tedious task. (Remind: Always initialize variables.)
class CPlayer {public:
void SetMoney(int m) { money_ = m; }void SetNumLands(int l) { numLands_ = l; }// ...
private:int money_;int numLands_;// ...
};int main() {
CPlayer UncleATu;UncleATu.SetMoney(100000); // Tedious InitializationUncleATu.SetNumLands(0);// ...
}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200911
Purpose of Constructors
Even though you define a member function forinitialization, you may also forget to call it.
class CPlayer {public:
void Init() { money_ = 100000; numLands_ = 0; }// ...
private:int money_;int numLands_;// ...
};int main(){
CPlayer UncleATu;UncleATu.Init(); // What if we forget it?// ...
}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200912
Purpose of Constructors
The constructor is a simple and automatic way toinitialize the objects.class CPlayer {public:
CPlayer():money_(INIT_MONEY), numLands_(0) {}// ...
private:static const int INIT_MONEY = 100000;int money_;int numLands_;// ...
};int main(){
CPlayer UncleATu; // It is initialized automatically.// ...
}
Remember:Always Initialize Variables.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200913
Definition & Use of Constructors
We can define various constructors to satisfy ourneeds.
class CPlayer {public:
CPlayer() { ... } // default ctorCPlayer(const CPlayer &rhs) { ... } // copy ctorCPlayer(const std::string &name, bool isComp) { ... }// ...
};int main(){
CPlayer UncleATu;CPlayer LittleMei(“Mei”, false);CPlayer temp(LittleMei);CPlayer *ptrPlayer = new CPlayer(“PC1”, true);CPlayer arr[3] = {CPlayer(LittleMei),
CPlayer(“Mei, false)}// ...
}
Note.CPlayer UncleATu(); is a function declaration.
Note. arr[2] is initialized by the default ctor.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200914
Definition & Use of Constructors
Other invocations of copy constructors
void PassByValue(CPlayer p){}CPlayer ReturnByValue(){
CPlayer p;// ...return p;
}int main(){
CPlayer p;std::vector<CPlayer> vecPlayer(5);vecPlayer.puch_back(p);return 0;
}
(1) Take a class object as the function argument.
(3) Define a non-empty container object.(4) Insert a class object into a container.
(2) Take a class object as the return value.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200915
Definition & Use of Constructors
We may enforce the provision of necessaryarguments upon the clients.
class CPlayer {public:
CPlayer() { ... } // default ctorCPlayer(const &CPlayer rhs) { ... } // copy ctorCPlayer(const std::string &name, bool isComp) { ... }// ...
private:// ...
};int main(){
CPlayer UncleATu; // not allowed!CPlayer LittleMei(“Mei”, false);CPlayer temp(LittleMei);CPlayer *ptrPlayer = new CPlayer(“PC1”, true);// ...
}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200916
Definition & Use of Constructors
In practice, however, we almost always define thedefault constructor if we define at least oneconstructor.
#include <vector>#include <string>
class CPlayer {public:
CPlayer(const std::string &name, bool isHuman) { }};int main(){
std::vector<CPlayer> vecPlayer(5); // default ctor isCPlayer *ptrPlayer = new CPlayer [10]; // required.// ...
}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200917
Definition & Use of Constructors
We can define a default constructor separately or byproviding default arguments for all parameters.
#include <string>class CPlayer {public:
CPlayer() { }CPlayer(const std::string &name, bool isComp) { }
};
#include <string>class CPlayer {public:
CPlayer(const std::string &name = “”, bool isComp = false){}
};
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200918
Distinction between CopyConstructor and Copy AssignmentDefinition
Invocation
class CPlayer {public:
CPlayer () { }CPlayer(const CPlayer &rhs) { } // copy ctorCPlayer & operator = (const CPlayer &rhs) // copy assignment{ }
};
int main(){
CPlayer Basic, Posada;CPlayer ARod(Basic), Jeter = Basic;Posada = Basic;return 0;
}
Note. default ctor of CPlayeris invoked for Posada.See “Prefer Initialization to Assignment.”
複製人 vs. 整型
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200919
Distinction between CopyConstructor and Copy Assignment Invocation of copy constructor in the member
initialization list
class CPlayer {public:
CPlayer(const std::string &name,const CMagicItem &item):name_(name)
{magicItem_ = item;
}// ...
private:std::string name_;CMagicItem magicItem_;// ...
};
Note. default ctor of CMagicItemis invoked (if there exists) beforecopy assignment.See “Prefer Initialization to Assignment.”
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200920
Exercise for Constructors
OutputD1MD2C1NC2PQRSD3C3
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2009
Destructor
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200922
Use of Destructors
For a class, there can be multiple constructors but atmost one destructor.
The destructor has no parameter and no return type.Not every class needs a destructor.
class CXYZCord {public:
CXYZCord(int x, y, z): x_(x), y_(y), z_(z) {}private:
int x_, y_, z_;};
The above class needs no destructor.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200923
Use of Destructors
Destructor is usually used to release resource.
class CPlayer {public:
CPlayer(const char name[]){
name_ = new char [strlen(name)+1];strcpy(name_, name);
}~CPlayer(){
delete [] name_;}// ...
private:char *name_;// ...
};
In this example, std::string is better than char *.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200924
Exercise
DevC++4992D1D2D3C 9999 <- 2C 8888 <- 3PC 7777 <- 8888A 9999 <- 7777Bye 7777Bye 8888D4Bye 9999Bye 4Bye 3Bye 2Bye 1
VisualC++2005D1D2D3C 9999 <- 2C 8888 <- 3PC 7777 <- 8888Bye 8888A 9999 <- 7777Bye 7777D4Bye 9999Bye 4Bye 3Bye 2Bye 1
9999
88887777
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2009
Guidelines
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200926
Coding Rules & Guidelines
Know What Functions C++ Silently Writes and Calls. Prefer Initialization to Assignment. Define and Initialize Member Variables in the Same Order. Explicitly Disallow Undesired Compiler-generated
Functions. Prefer the Canonical Form of Assignment. Declare Destructors Virtual in Polymorphic Base Classes. Never Call Virtual Functions during Construction and
Destruction. Copy and Destroy Consistently. Avoid Slicing.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200927
Exercise for Default Constructor (1)
Are they initialized? No.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200928
Exercise for Default Constructor (2)
Are they initialized? The first one is.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200929
Exercise for Default Constructor (3)
Are they initialized? The second one is.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200930
Know What Functions C++ SilentlyWrites and Calls.The compiler may generate the following
functions for you if necessary (and possible).Default constructorCopy constructorDestructorCopy assignment
All these generated functions are publicand inline.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200931
Know What Functions C++ SilentlyWrites and Calls.Default constructor
It is generated when the class has non-static datamembers with default constructors.
class Comp {public:
Comp() {}// ...};class Car {public:
// ...private:
Comp component_;int price_;
};int main() {
Car mycar;return 0;
}
Note. price_ is not initialized.
Car():component_(){}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200932
Know What Functions C++ SilentlyWrites and Calls.Default constructor
It is generated when the class is derived from abase class with the default constructor.
class Car {public:
Car() {}// ...};class BMW : public Car {public:// ...};int main(){
BMW mycar;return 0;
}
Note. Only the Car part is initialized.
BMW():Car(){}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200933
Know What Functions C++ SilentlyWrites and Calls.Default constructor
Generation of default constructors for the followingCar and BMW classes will fail.
class Comp {public:
Comp(int val) {}// ...};class Car {private:
Comp component_;int price_;
};int main() {
Car mycar; // error!return 0;
}
class Car {public:
Car(int val) {}// ...};class BMW : public Car {// ...};int main(){
BMW mycar; // error!return 0;
}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200934
Know What Functions C++ SilentlyWrites and Calls.Default constructor
Generation of default constructors for the followingRefDM and ConstDM classes will fail.
class RefDM {private:
int &refInt_;};int main() {
RefDM r; // error!return 0;
}
class ConstDM {private:
const int VAL_;};int main() {
ConstDM r; // error!return 0;
}
Note. const or reference-type data members must always be initialized in the member initialization list.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200935
Know What Functions C++ SilentlyWrites and Calls.Default constructor
In the two examples in the previous slide, we needto define the constructor definitely and to use themember initialization list.
class RefDM {public:
RefDM(int &v):refInt_(v) {}?//RefDM(int &v) { refInt_ = v; }private:
int &refInt_;};int main() {
int num;RefDM r(num);return 0;
}
class ConstDM {public:
ConstDM(int v):VAL_(v) {}?//ConstDM(int v) { VAL_ = v; }private:
const int VAL_;};int main() {
ConstDM r(1);return 0;
}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200936
Know What Functions C++ SilentlyWrites and Calls.Default constructor
No default constructor is generated by thecompiler for the following two classes.
class OnlyPrimitive {public:
// ...private:
char ch_;int val_;double *ptr_;
};
class HaveSpecificCtor {public:
HaveSpecificCtor(int v);private:
// ...};
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200937
Know What Functions C++ SilentlyWrites and Calls.Copy constructor (Memberwise copy construction)
It is generated when you do not provide it.
class Comp {public:
Comp() {}Comp(const Comp& rhs) { }
// ...};class Car {public:
// ...private:
Comp component_;int price_;
};int main(){
Car mycar1, mycar2(mycar1);return 0;
}
Car(const Car &rhs):component_(rhs.component_),price_(rhs.price)
{}
Call copy ctor of Comp,which is a user-defined class..
Copy each bits since intis a primitive type.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200938
Know What Functions C++ SilentlyWrites and Calls.Copy constructor
Is there any problem for the compiler to generatecopy constructor for us?
class RefDM {public:
RefDM(int &v):refInt_(v) {}private:
int &refInt_;};int main() {
int num;RefDM r(num);RefDM r2(r);return 0;
}
class ConstDM {public:
ConstDM(int v):VAL_(v) {}private:
const int VAL_;};int main() {
ConstDM r(1);ConstDM r2(r);return 0;
}
Ans:No.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200939
Know What Functions C++ SilentlyWrites and Calls.Destructor
It is generated in the same situations as what wehave mentioned for default constructor.
class Comp {public:
~Comp() {}// ...};class Car {public:
// ...private:
Comp component_;int price_;
};int main() {
Car mycar;return 0;
}
class Car {public:
~Car() {}// ...};class BMW : public Car {public:
// ...};int main(){
BMW mycar;return 0;
}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200940
Know What Functions C++ SilentlyWrites and Calls.Copy assignment (Memberwise copy assignment)
It is generated when you do not provide it.
class Car {public:
// ...private:
Comp component_;int price_;
};int main(){
Car mycar1, mycar2;mycar2 = mycar1;return 0;
}
Car & operator = (const Car &rhs){
component_ = rhs.component_;price_ = rhs.price_;
}
If Comp does not define the copy assignmentoperator, the compiler will generate it recursively.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200941
Know What Functions C++ SilentlyWrites and Calls.Copy assignment
Generation of copy assignment operators for thefollowing RefDM and ConstDM classes will fail.
class RefDM {public:
RefDM(int &v):refInt_(v) {}private:
int &refInt_;};int main() {
int num, num2;RefDM r(num), r2(num2);r = r2; // error!return 0;
}
class ConstDM {public:
ConstDM(int v):VAL_(v) {}private:
const int VAL_;};int main() {
ConstDM r(1), r2(2);r = r2; // error!return 0;
}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200942
Know What Functions C++ SilentlyWrites and Calls. The compiler-generated copy constructor and copy
assignment do not always work well.class CPlayer {public:
CPlayer(const char name[]) {name_ = new char [strlen(name)+1];strcpy(name_, name);
}~CPlayer() { delete [] name_; }// ...
private:char *name_;// ...
};int main() {
CPlayer p1(“Wade”),p2(p1),p3(“James”);
p3 = p1;}
Example1
Mistakes:1. memory leak2. delete three times (undefined behaviors)(In this example, std::string is better than char *.)
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200943
Know What Functions C++ SilentlyWrites and Calls. The compiler-generated copy constructor and copy
assignment do not always work well.
class CPlayer {public:
CPlayer() {uniqueID_ = NameDatabase_.GetID();
}// ...
private:static CNameDatabase NameDatabase_;int uniqueID_;// ...
};int main() {
CPlayer p1,p2(p1),p3;
p3 = p1;}
Example2
Mistakes:1. ID is no longer unique.2. ID is not re-collected.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200944
Know What Functions C++ SilentlyWrites and Calls. The compiler-generated copy constructor and copy
assignment do not always work well. Solutions:
(1) Provide our own copy constructor and copy assignment.(2) Explicitly Disallow Undesired Compiler-generatedFunctions.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200945
Prefer Initialization to Assignment.
An important concept –the execution of constructorconsists of two stages.
class CPlayer {public:
CPlayer(const std::string &name):name_(name)
{money_ = INIT_MONEY;numLands_ = 0;
}// ...
private:std::string name_;static const int INIT_MONEY = 100000;int money_;int numLands_;// ...
};
Initialization phase
Computation phase
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200946
Prefer Initialization to Assignment.
Initialize the class-type objects directly is more efficient thancalling default constructors and then setting the values.
class CPlayer {public:
CPlayer(const std::string &name):name_(name),money_(INIT_MONEY),numLands_(0)
{}// ...
private:std::string name_;static const int
INIT_MONEY = 100000;int money_;int numLands_;// ...
};
class CPlayer {public:
CPlayer(const std::string &name){
name_ = name;money_ = INIT_MONEY;numLands_ = 0;
}// ...
private:std::string name_;static const int
INIT_MONEY = 100000;int money_;int numLands_;// ...
};
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200947
Prefer Initialization to Assignment.
Even though the data members are primitive types or need noinitial values, it is more popular to initialize them in the memberinitialization list (for consistency and ease of maintenance.)class CPlayer {public:
CPlayer(const std::string &name):name_(name),money_(INIT_MONEY),numLands_(0),someValue()
{}// ...
private:std::string name_;static const int INIT_MONEY = 100000;int money_;int numLands_;int someValue_;// ...
};
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200948
Prefer Initialization to Assignment.
When there are multiple constructors, we can move theinitialization of primitive-type data members to one memberfunction to avoid repeating, boring, and error-prone actions.
class CPlayer {public:
CPlayer(const std::string &name):name_(name),money_(INIT_MONEY),numLands_(0),someValue()
{}CPlayer(...)
:name_(name),money_(INIT_MONEY),numLands_(0),someValue()
{}
// ...};
class CPlayer {public:
CPlayer(const std::string &name):name_(name) {
Init();}CPlayer(...)
:name_(name) {Init();
}private:
void Init() {money_ = INIT_MONEY;numLands_ = 0;someValue;
}// ...};
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200949
Prefer Initialization to Assignment.
Name return value optimization is easier forinitialization than for assignment.
class CPlayer{public:CPlayer(int id = 0):id_(id) {
cout << “ctor:" << id_ << endl;}CPlayer(const CPlayer &rhs):id_(rhs.id_){
cout << "copy ctor:" << id_ << endl;}CPlayer & operator= (const CPlayer &rhs){
cout << "copy assignment:" << id_<< " <= " << rhs.id_ << endl;
return *this;}
private:int id_;
};
CPlayer Simple(){
CPlayer local(1);return local;
}int main(){
CPlayer x = Simple();cout << “----------\n”;CPlayer y;y = Simple();
}
Result (DevC++ 4992, VisualC++ 2005)
ctor:1-----------ctor:0ctor:1copy assignment: 0 <= 1
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200950
Prefer Initialization to Assignment.
Name return value optimization is easier forinitialization than for assignment.CPlayer ComplexFunc(){
CPlayer a(3), b(4);if (true) {
return a;}else {
return b;}
}int main(){
CPlayer x = ComplexFunc();cout << “----------\n”;CPlayer y;y = ComplexFunc();return 0;
}
Result (DevC++ 4992, VisualC++ 2005)
ctor:3ctor:4copy ctor:3-----------ctor:0ctor:3ctor:4copy ctor:3copy assignment: 0 <= 3
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200951
Define and Initialize MemberVariables in the Same Order.
class Employee{public:
Employee(std::string &firstName, std::string &lastName):firstName_(firstName),lastName_(lastName),email_(firstName_ + “.” + lastName_ + “@ntnu.edu.tw”)
{}private:
std::string email_, firstName_, lastName_;};int main(){
Employee wrongEmail(“tc”, “chiang”);return 0;
}
What’s wrong?
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200952
Define and Initialize MemberVariables in the Same Order. Solution A
Make the order of initialization consistent with the order ofdefinition.
class Employee {public:
Employee(std::string &firstName, std::string &lastName):firstName_(firstN),lastName_(lastName),email_(firstName_ + “.” + lastName_ + “@ntnu.edu.tw”) {}
private:std::string firstName_, lastName_, email_;
};
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200953
Define and Initialize MemberVariables in the Same Order. Solution B
Put the dependent behavior after initialization.
Solution CAvoid the dependent behavior.
class Employee {public:
Employee(std::string &firstName, std::string &lastName):firstName_(firstN),lastName_(lastName){ email_ = firstName_ + “.” + lastName_ + “@ntnu.edu.tw”; }
};
class Employee {public:
Employee(std::string &firstName, std::string &lastName):firstName_(firstN),lastName_(lastName),email_(firstName + “.” + lastName + “@ntnu.edu.tw”) {}
};
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2009
Exercise
Write a class to simulate std::string.
class String{public:
// 1. default constructor// 2. copy constructor// 3. constructor with one parameter// with type const char *// 4. destructor// 5. size()
private:char *str_;
};
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200955
Explicitly Disallow UndesiredCompiler-generated Functions. As mentioned, the compiler generates copy
constructor and copy assignment automatically for us.In some cases, however, we do not want them.
class CPlayer {public:
CPlayer() {uniqueID_ = NameDatabase_.GetID();
}// ...
private:static CNameDatabase NameDatabase_;int uniqueID_;// ...
};int main() {
CPlayer p1, p2(p1), p3;p3 = p1;
}
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200956
Explicitly Disallow UndesiredCompiler-generated Functions. Solution: Define copy constructor and copy
assignment definitely and make them private.
class CPlayer {public:
CPlayer() {uniqueID_ = NameDatabase_.GetID();
}// ...
private:CPlayer(const CPlayer &) {}CPlayer & operator = (const CPlayer &) {}static CNameDatabase NameDatabase_;int uniqueID_;// ...
};int main() {
CPlayer p1, p2(p1), p3;p3 = p1;
} Compilation error
Is it completely safe?(Who can invoke the private member functions?)
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200957
Explicitly Disallow UndesiredCompiler-generated Functions. A problem that is not solved by our solution.
class CPlayer {public:
CPlayer() {uniqueID_ = NameDatabase_.GetID();
}void Accident() {
CPlayer p1, p2(p1), p3;p3 = p1;
}// ...
private:CPlayer(const CPlayer &) {}CPlayer & operator = (const CPlayer &) {}static CNameDatabase NameDatabase_;int uniqueID_;// ...
};
Copying is still allowed in the member function(and CPlayer’s friends).
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200958
Explicitly Disallow UndesiredCompiler-generated Functions. Solution+: Just declare them, but do not define them.
class CPlayer {public:
CPlayer() {uniqueID_ = NameDatabase_.GetID();
}void Accident() {
CPlayer p1, p2(p1), p3;p3 = p1;
}// ...
private:CPlayer(const CPlayer &);CPlayer & operator = (const CPlayer &);static CNameDatabase NameDatabase_;int uniqueID_;// ...
};
Linkage error
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200959
Explicitly Disallow UndesiredCompiler-generated Functions. Solution++: Define a base class to avoid copying.
All copying actions will cause errors during compilation.(It is better to detect the errors earlier.)
class Uncopyable {protected:
Uncopyable() {}~Uncopyable() {}
private:Uncopyable(const Uncopyable &);Uncopyable& operator = (const Uncopyable &);
};class CPlayer : private Uncopyable {
// Do not define copy constructor & copy assignment
};
FAQ1: Why not public or private?
FAQ2: Why not public?
FAQ1: Because we do not want to define Uncopyable objects but want to define CPlayer objects.FAQ2: private inheritance means “is implemented in terms of”, where public inheritance means “is a”.
“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 200960
Explicitly Disallow UndesiredCompiler-generated Functions. Summary:
Ensure your class provides correct copying actions,you have the following options: Explicitly disable copying. Explicitly define your own copying functions. Use the compiler-generated version, AND use comments to
let readers know that you do not ignore the above twooptions carelessly.
Note: Copying & standard containers Disable copying implies that you can not put your objects
into standard containers. However, you can still simulate it through the aid of (smart)
pointers.