类的拷贝管理
拷贝控制:
拷贝构造函数,拷贝赋值运算符,移动构造函数,移动赋值运算符,析构函数
//拷贝构造函数// class Sales_data { public: Sales_data(const Sales_data &); Sales_data & operator = (const Sales_data &); private: string bookNo; int uints_sold = 0; double revenue = 0.0; }; Sales_data::Sales_data(const Sales_data &orig) : bookNo(orig.bookNo), uints_sold(orig.uints_sold), revenue(orig.revenue) {}
如果没有定义拷贝构造函数,编译器会定义一个。即使自己定义了拷贝构造函数,编译器也会合成一个。
Sales_data::Sales_data(const Sales_data &orig) : bookNo(orig.bookNo), uints_sold(orig.uints_sold), revenue(orig.revenue) {}
拷贝初始化:
直接初始化:string dot(10,'.');
拷贝初始化:string s2 = dot;
//拷贝构造函数发生:将对象作为实参传给非引用的形参
//返回一个非引用类型的对象
//使用=进行拷贝
1 Sales_data & Sales_data::operator = (const Sales_data &rhs) { 2 return *this; 3 }//赋值运算符 4 extern vector<vector<int>> Permutations(vector<int > &nums);
三五法则
//需要析构函数的类也需要拷贝和赋值操作
class HasPtr { public: HasPtr(const string &s = string()) :ps(new std::string(s)), i(0) {}; ~HasPtr() { delete ps; } private: string *ps; int i; };
//使用默认的拷贝构造函数和拷贝赋值运算符,导致多个HasPtr对象指向相同内存
HasPtr f(HasPtr hp) { HasPtr ret = hp; return ret; }
//ret和hp的ps以及传入实参都指向统一内存,析构函数调用时会出现delete两次相同内存,出新错误
需要拷贝操作的类也需要赋值操作
class numbered { public: numbered(const numbered &num) = delete;//删除阻止拷贝 numbered() = default;//显示 private: int mysn; };//析构函数不能是删除的成员删除的成员 struct PersonInfo { string name; vector<string> phones; };
1 //行为像值的类 2 class HasPtr { 3 public: 4 HasPtr(const string &s = string()) :ps(new std::string(s)), i(0) {}; 5 HasPtr(const HasPtr &p) : 6 ps(new std::string(*p.ps)), i(p.i) {}; 7 8 ~HasPtr() { delete ps; } 9 private: 10 string *ps; 11 int i; 12 }; 13 HasPtr& HasPtr::operator = (const HasPtr &rhs) { 14 auto newp = new string(*rhs.ps); 15 delete ps;//释放旧内存 16 ps = newp; 17 i = rhs.i; 18 /*delete ps; 19 ps = new string(*(rhs.ps)); 20 i = rhs.i;*///自赋值会出现错误,比如rhs和本对象是通过一个对象 21 return *this; 22 } 23 24 //行为像指针的类 25 //最好的方法是使用shared_ptr来管理类中的资源,第二种是引用计数 26 //除了初始化对象外,每个构造函数要创建一个引用计数 27 //拷贝构造函数不分配新的计数器而是拷贝给顶对象的数据成员,包括计数器,拷贝构造函数递增共享的计数器 28 //析构函数递减共享的计数器 29 //拷贝赋值运算递增右侧运算对象的计数器,递减左侧对象的计数器 30 31 32 33 //将计数器保存在动态内存中 34 class HasPtr { 35 public: 36 //构造函数分配新的string和新的计数器,计数器值置1 37 HasPtr(const string &s = string()) :ps(new std::string(s)), i(0),use(new std::size_t(1)) {}; 38 HasPtr(const HasPtr &p) : 39 ps(p.ps), i(p.i), use(p.use) { 40 ++*use;//递增计数 41 };//ps保存拷贝对象的内存 42 43 ~HasPtr() { } 44 private: 45 string *ps; 46 int i; 47 std::size_t *use; 48 }; 49 HasPtr::~HasPtr() { 50 if (--*use == 0) { 51 delete ps; 52 delete use; 53 } 54 } 55 HasPtr& HasPtr::operator = (const HasPtr &rhs) { 56 ++*rhs.use; 57 if (--*use == 0) { 58 delete ps; 59 delete use; 60 } 61 ps = rhs.ps; 62 i = rhs.i; 63 use = rhs.use; 64 return *this; 65 } 66 class HasPtr { 67 68 friend void swap(HasPtr&, HasPtr&); 69 HasPtr(const string &s = string()) :ps(new std::string(s)), i(0) {}; 70 ~HasPtr() { delete ps; } 71 private: 72 string *ps; 73 int i; 74 75 }; 76 inline void swap(HasPtr &lhs, HasPtr &rhs) { 77 using std::swap; 78 swap(lhs.ps, rhs.ps); 79 swap(lhs.i, rhs.i); 80 }