+ All Categories
Home > Documents > Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor,...

Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor,...

Date post: 14-Jul-2020
Category:
Upload: others
View: 1 times
Download: 0 times
Share this document with a friend
21
Ctor, Dtor, and Assignment,The Practice of Programming, CSIE@NTNU, 2010 55 Explicitly Disallow Undesired Compiler-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; }
Transcript
Page 1: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201055

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;

}

Page 2: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201056

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?)

Page 3: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201057

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).

Page 4: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201058

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

Page 5: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201059

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”.

Page 6: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201060

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.

Page 7: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201061

Prefer the Canonical Form ofAssignment. Let your operator= be a member function with one

of the following two signatures*:T& operator=(const T&); // classic

T& operator=(T); // if you want a copy of the argument

Return a reference to *this. Don’t return const T&.

Copy all parts of an object.

Handle assignment to self. Avoid making your assignment operator virtual.

If you really need it, prefer to provide a named functioninstead (e.g. virtual void Assign(const T&); )

* An exception is std::auto_ptr. (See item 10 in C++ Gotchas.)

Page 8: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201062

Prefer the Canonical Form ofAssignment.Return a reference to *this. Don’t return const T&.class CPlayer {public:

CPlayer & operator = (const CPlayer &) { // ...return *this;

}};void func(int &) { // ...}void func(CPlayer &) { // ...}int main(){

int n1, n2, n3;n1 = n2 = n3;func(n1 = n2);

CPlayer p1, p2, p3;p1 = p2 = p3;func(p1 = p2);return 0;

}

Reason:Since this behavior is followed by all primitivetypes and STL types, just follow it.

Page 9: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201063

Prefer the Canonical Form ofAssignment.Copy all parts of an object.

class CPlayer {public:// no copy assignment is defined.private:

std::string name_;int money_;

// ...};int main(){

CPlayer p1, p2;p1 = p2;

}

class CPlayer {public:CPlayer & operator= (const CPlayer &rhs){

name_ = rhs.name_;money_ = rhs.money_;return *this;

}private:

std::string name_;int money_;

// ...};int main(){

CPlayer p1, p2;p1 = p2;

}

Compiler-generated copying functionswork well.

When you define your own copyingfunctions (and ctors), remember toupdate them when you add newdata members.

// add a new memberint someValue_;

// add a new memberint someValue_;

Page 10: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201064

Prefer the Canonical Form ofAssignment.Copy all parts of an object.

class CPowerPlayer : public CPlayer {public:

CPowerPlayer():power_(0) {

}CPowerPlayer(const CPowerPlayer &rhs)

:power_(rhs.power_) {}CPowerPlayer & operator = (const CPowerPlayer &rhs) {

power_ = rhs.power_;}

private:int power_;

};int main(){

CPowerPlayer pp1;pp1.SetName(“Jeter”);CPowerPlayer pp2(pp1), pp3;pp3 = pp1;

}

class CPlayer {private:

std::string name_;int money_;

};

What’s wrong with them?

Page 11: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201065

Prefer the Canonical Form ofAssignment.Copy all parts of an object.

class CPowerPlayer : public CPlayer {public:

// ...CPowerPlayer(const CPowerPlayer &rhs)

:CPlayer(rhs),power_(rhs.power_) {

}CPowerPlayer & operator = (const CPowerPlayer &rhs) {

CPlayer::operator=(rhs);power_ = rhs.power_;

}private:

int power_;};int main(){

CPowerPlayer pp1;pp1.SetName(“Jeter”);CPowerPlayer pp2(pp1), pp3;pp3 = pp1;

}

When you write a copying function, ensure that(1) copy all local data members(2) call suitable copying functions for all base

classes.

(In this example, we don’t need to write the twocopying functions by ourselves. The compiler’sversion is fine.)

Page 12: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201066

Prefer the Canonical Form ofAssignment.Copy all parts of an object.

class CPowerPlayer : public CPlayer{public:

CPowerPlayer():power_(0) {}// CPowerPlayer(const CPowerPlayer &rhs) {}// CPowerPlayer & operator = (const CPowerPlayer &) {}

int power_;};

int main(){

CPowerPlayer pp1;pp1.name_ = "pp1";CPowerPlayer pp2(pp1), pp3;pp3 = pp1;cout << pp2.name_ << ' ' << pp3.name_ << endl;return 0;

}

class CPlayer{public:

CPlayer():name_("default"),money_(0) {}

std::string name_;int money_;

};

Before remarking: default defaultAfter remarking: pp1 pp1

Page 13: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201068

Prefer the Canonical Form ofAssignment.Handle assignment to self.

Am I stupid to do self-assignment?

int main(){

CPlayer me, you;CPlayer players[5];CPlayer *ptr1, *ptr2;CPlayer &ref = you;int i, j;

// ...

me = me; // I am not that stupid.players[i] = players[j]; // Am I sure that i j?*ptr1 = *ptr2; // Am I sure that ptr1 ptr2?ref = *ptr1; // Am I sure that ref *ptr1?

return 0;}

Page 14: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201069

Prefer the Canonical Form ofAssignment.Handle assignment to self.

Wrong implementation –version 1.0

class CImage { ... };

class CPlayer {public:

CPlayer & operator = (const CPlayer &rhs);private:

CImage *image_;// ...};

CPlayer & CPlayer::operator= (const CPlayer &rhs){

image_ = new CImage(*rhs.image_);return *this;

} memory leak

Page 15: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201070

Prefer the Canonical Form ofAssignment.Handle assignment to self.

Wrong implementation –version 1.1

class CImage { ... };

class CPlayer {public:

CPlayer & operator = (const CPlayer &rhs);private:

CImage *image_;// ...};

CPlayer & CPlayer::operator= (const CPlayer &rhs){

delete image_;image_ = new CImage(*rhs.image_);return *this;

} no dealing with self-assignment

Page 16: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201071

Prefer the Canonical Form ofAssignment.Handle assignment to self.

Wrong implementation –version 2

class CImage { ... };

class CPlayer {public:

CPlayer & operator = (const CPlayer &rhs);private:

CImage *image_;// ...};

CPlayer & CPlayer::operator= (const CPlayer &rhs){

if (this == &rhs) return *this;

delete image_;image_ = new CImage(*rhs.image_);return *this;

}not exception-safe(what if new CImage throws exception?)

Page 17: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010

Prefer the Canonical Form ofAssignment.#include <iostream>#include <new>using namespace std;

void MemAlloc(char **p, int t){

cout << "Before allocation..." << endl;*p = new char [1024*1024*500]; // 500 MB at a timecout << "Allocate " << 500*t << " MB successfully." << endl;

}

int main(){

const int TrialNum = 100;char *p[TrialNum];for (int i=1; i<=TrialNum; i+=1){

try {MemAlloc(&p[i], i);

}catch (bad_alloc &ba) {

cout << "Memory allocation failed." << endl;break;

}cout << "Back from MemAlloc.\n" << endl;

}}

Before allocation...Allocate 500 MB successfully.Back from MemAlloc.

Before allocation...Allocate 1000 MB successfully.Back from MemAlloc.

Before allocation...Allocate 1500 MB successfully.Back from MemAlloc.

Before allocation...Memory allocation failed.

An example of exception caused byunsuccessful memory allocation.

Page 18: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201073

Prefer the Canonical Form ofAssignment.Handle assignment to self.

Correct implementation –version 1

class CImage { ... };

class CPlayer {public:

CPlayer & operator = (const CPlayer &rhs);private:

CImage *image_;// ...};

CPlayer & CPlayer::operator= (const CPlayer &rhs){

CImage *pOrig = image_;image_ = new CImage(*rhs.image_);delete pOrig;return *this;

}self-assignment safeexception safe

Page 19: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201074

Prefer the Canonical Form ofAssignment.Handle assignment to self.

Correct(?) implementation –version 1 (Is it still exception-safe?)

class CImage { ... };

class CPlayer {public:

CPlayer & operator = (const CPlayer &rhs);private:

CImage *image1_, *image2_;// ...};CPlayer & CPlayer::operator= (const CPlayer &rhs){

CImage *pOrig = image1_;image1_ = new CImage(*rhs.image1_);delete pOrig;pOrig = image2_;image2_ = new CImage(*rhs.image2_);delete pOrig;return *this;

}not strong exception-safe(what if new CImage(*rhs.image2) throws exception?)

Page 20: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 201075

Prefer the Canonical Form ofAssignment.Handle assignment to self.

The most recommended implementation (copy and swap tech.)

class CPlayer {public:

CPlayer(const CPlayer &rhs) { ... }CPlayer & operator = (const CPlayer &rhs);void swap(CPlayer &rhs) { ... }

// ...};CPlayer & CPlayer::operator= (const CPlayer &rhs){

CPlayer temp(rhs);swap(temp);return *this;

}

In principle, the swap() function should be no-fail.

If self-assignment is frequent due to reference aliasing or other reasons, it’s okay to still checkfor self-assignment anyway as an optimization check to avoid needless work.

Page 21: Explicitly Disallow Undesired Compiler-generated Functions.web.ntnu.edu.tw/~tcchiang/tpp/3_Ctor, dtor, and assignment (III).pdf · “Ctor, Dtor, and Assignment,”The Practice of

“Ctor, Dtor, and Assignment,”The Practice of Programming, CSIE@NTNU, 2010

Exercise

Add more operators to your simulated Stringclass.

class String{public:

// 1. default constructor// 2. copy constructor// 3. constructor with one parameter with type const char *// 4. destructor// 5. size()// 6. c_str()// 7. copy assignment// 8. operator []// 9. operator +=

private:char *str_;

};// A. operator <// B. operator <<

76


Recommended