类的拷贝管理

拷贝控制:
拷贝构造函数,拷贝赋值运算符,移动构造函数,移动赋值运算符,析构函数

//拷贝构造函数//
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 }

 

posted @ 2018-02-07 12:59  BingzzzZZZ  阅读(222)  评论(0编辑  收藏  举报