行为像(值/指针)的类

行为像值的类

  • 每个类的数据成员都有一份自己的拷贝.不共享数据成员.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    #include <iostream>
    #include <string>
    #include <memory>

    using namespace std;

    class HasPtr{
    public:
    HasPtr():ps(make_shared<string>()),num(0) {}
    HasPtr(const string& s,int sz=0):ps(make_shared<string>(s)),num(sz) {}
    HasPtr(const HasPtr& rhs) {
    ps = make_shared<string>(*rhs.ps);
    num = rhs.get_number();
    }
    HasPtr& operator= (const HasPtr& rhs) {
    ps = make_shared<string>(*rhs.ps);
    return *this;
    }
    int get_number() const { return num; }
    int get_number() { return num; }
    shared_ptr<string> get_ptr() { return ps; }
    shared_ptr<string> get_ptr() const { return ps; }
    private:
    int num;
    shared_ptr<string> ps;
    };
    int main() {
    HasPtr temp1("hello");
    HasPtr temp2 = temp1;
    cout << "string s= " << *temp1.get_ptr() << endl;
    cout << "temp2 s = " << *temp2.get_ptr() << endl;


    return 0;
    }

行为像指针的类

  • 直接使用shared_ptr<>来管理资源
  • 通过普通指针设计引用计数来实现资源管理

    引用计数设计原则

  1. 普通构造创建计数器
  2. 拷贝构造函数,拷贝数据成员,或者指针本身,同时计数器自增
  3. 拷贝赋值运算,递减左侧运算对象计数器,递增右侧运算对象计数器,并判断计数器==0
  4. 析构递减计数器,==0回收内存
    HasPtr_ptr1.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    #include <iostream>
    #include <string>

    using namespace std;

    class HasPtr {
    public:
    HasPtr(const string& s = string(),int sz = 0):ps(new string(s)),i(sz),use(new size_t(1)) {}
    HasPtr(const HasPtr& rhs):
    ps(rhs.ps),i(rhs.i),use(rhs.use) {
    ++*use;
    }
    HasPtr& operator= (const HasPtr& rhs) {
    ++*rhs.use;
    if (--*use == 0) {
    cout << "reference count = 0" << endl;
    delete ps;
    delete use;
    }
    ps = rhs.ps;
    i = rhs.i;
    use = rhs.use;
    return *this;
    }
    ~HasPtr() {
    if (--*use == 0) {
    cout << "reference count = 0" << endl;
    delete ps;
    delete use;
    }
    }
    string get_ps() { return *ps; }
    string get_ps() const { return *ps; }
    int get_i() { return i; }
    int get_i() const { return i; }
    private:
    string* ps;
    int i;
    size_t* use;
    };


    int main() {
    HasPtr temp1("hello",11);
    HasPtr temp2("world",23);
    temp1 = temp2;
    cout << "temp1.i " << temp1.get_i() << "\n";
    HasPtr temp3 = temp2;
    cout << "temp3.i " << temp3.get_i() << "\n";
    return 0;
    }
    HasPtr_ptr2.cpp
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    #include <iostream>
    #include <string>
    #include <vector>
    #include <initializer_list>

    using namespace std;

    class HasPtr {
    public:
    HasPtr():ps(new vector<string>),use(new int(1)) {}
    HasPtr(initializer_list<string> i1):ps(new vector<string>(i1)),use(new int(1)) {}

    HasPtr(HasPtr& rhs):ps(rhs.ps),use(rhs.use) { ++*use; }

    HasPtr& operator= (HasPtr& rhs) {
    ++*rhs.use;
    if (--*use == 0) {
    delete ps;
    delete use;
    }
    use = rhs.use;
    ps = rhs.ps;

    return *this;
    }
    ~HasPtr() {
    if (--*use == 0) {
    cout << " destructor reference count " << endl;
    delete ps;
    delete use;
    }
    }
    void push_back(const string& t) { ps->push_back(t); }
    void pop_back() {
    if (!ps->empty())
    ps->pop_back();
    else
    cout << " vector<string> is empty " << endl;
    }
    size_t size() const { return ps->size(); }
    size_t get_use() const { return *use; }
    private:
    vector<string>* ps;
    int* use;
    };
    int main() {
    HasPtr temp1 = {"a","b","c"};
    {
    HasPtr temp2 = temp1;
    temp2.push_back("d");
    cout << "temp2.size()= " << temp2.size() << endl;
    cout << "temp1.size()= " << temp1.size() << endl;
    cout << "temp1.use = " << temp1.get_use() << " temp2.use = " << temp2.get_use() << endl;
    }

    cout << "temp1.use = " << temp1.get_use() << endl;
    return 0;
    }

书上给出的标程:
HasPtr_ptr3.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>
#include <string>

using namespace std;

class HasPtr {
public:
HasPtr(const string& s=string()):ps(new string(s)),i(0),use(new size_t(1)) {}
HasPtr(const HasPtr& p):
ps(p.ps),i(p.i),use(p.use) { ++*use; }
HasPtr& operator=(const HasPtr& rhs) {
++*rhs.use;
if (--*use == 0) {
delete ps;
delete use;
}
ps = rhs.ps;
use = rhs.use;
i = rhs.i;
return *this;
}
HasPtr& operator=(const string& rhs) {
*ps = rhs;
return *this;
}
string& operator* () { return *ps; }
~HasPtr() {
if (--*use == 0) {
delete ps;
delete use;
}
}
private:
string* ps;
int i;
size_t* use;
};
int main() {
HasPtr h("ni mom!");
HasPtr h2 = h;
h = "hi dad!";
cout << "h: " << *h << endl;
cout << "h2: " << *h2 << endl;
return 0;
}

StrBlob类通过定义拷贝控制操作使其行为像值

my_StrBlob.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
#ifndef MY_STRBLOB_H
#define MY_STRBLOB_H

#include <vector>
#include <string>
#include <initializer_list>
#include <memory>
#include <stdexcept>

using namespace std;

class StrBlobPtr;
class StrBlob {
friend class StrBlobPtr;
public:
using size_type = vector<string>::size_type;

StrBlob():data(make_shared<vector<string>>()) {}
StrBlob(initializer_list<string> i1):data(make_shared<vector<string>>(i1)) {}
StrBlob(vector<string>* p):data(p) {}
StrBlob(StrBlob& rhs):data(make_shared<vector<string>> (*rhs.data)) {}
StrBlob& operator= (StrBlob& rhs) {
data = make_shared<vector<string>> (*rhs.data);
return *this;
}

size_type size() const { return data->size(); }
bool empty() const { return data->empty(); }

void push_back(const string& t) { data->push_back(t); }
void pop_back();

string& front();
string& front() const;

string& back();
string& back() const;

StrBlobPtr begin();
StrBlobPtr end();

StrBlobPtr begin() const;
StrBlobPtr end() const;

private:
shared_ptr<vector<string>> data;
void check(size_type i,const string& msg) const;
};

inline void StrBlob::check(size_type i,const string& msg) const {
if(i >= data->size())
throw out_of_range(msg);
}

inline string& StrBlob::front() {
check(0,"front");
return data->front();
}
inline string& StrBlob::front() const {
check(0,"const front");
return data->front();
}

inline string& StrBlob::back() {
check(0,"back");
return data->back();
}
inline string& StrBlob::back() const {
check(0,"const back");
return data->back();
}

inline void StrBlob::pop_back() {
check(0,"ss");
data->pop_back();
}

class StrBlobPtr {
friend bool eq(const StrBlobPtr&,const StrBlobPtr&);
public:
StrBlobPtr():curr(0) {}
StrBlobPtr(StrBlob& a,size_t sz = 0):wptr(a.data),curr(sz) {}
StrBlobPtr(const StrBlob& a,size_t sz = 0):wptr(a.data),curr(sz) {}

string& deref() const;
string& deref(int off) const;
StrBlobPtr& incr();
StrBlobPtr& decr();
private:
shared_ptr<vector<string>> check(size_t,const string&) const;
weak_ptr<vector<string>> wptr;
size_t curr;
};
inline shared_ptr<vector<string>> StrBlobPtr::check(size_t i,const string& msg) const {
auto ret = wptr.lock();
if (!ret)
throw runtime_error("x");
if (i >= ret->size())
throw out_of_range(msg);
return ret;
}
inline string& StrBlobPtr::deref() const {
auto p = check(curr," ");
return (*p)[curr];
}
inline string& StrBlobPtr::deref(int off) const {
auto p = check(curr + off," ");
return (*p)[curr + off];
}

inline StrBlobPtr& StrBlobPtr::incr() {
check(curr,"curr range");
++curr;
return *this;
}
inline StrBlobPtr& StrBlobPtr::decr() {
curr--;
check(-1,"d");
return *this;
}

inline StrBlobPtr StrBlob::begin() {
return StrBlobPtr(*this);
}
inline StrBlobPtr StrBlob::end() {
auto ret = StrBlobPtr(*this,data->size());
return ret;
}
inline StrBlobPtr StrBlob::begin() const {
return StrBlobPtr(*this);
}
inline StrBlobPtr StrBlob::end() const {
auto ret = StrBlobPtr(*this,data->size());
return ret;
}

inline bool eq(const StrBlobPtr& lhs,const StrBlobPtr& rhs) {
auto l = lhs.wptr.lock();
auto r = rhs.wptr.lock();
if (l == r)
return (!r || lhs.curr == rhs.curr);
else
return false;
}
inline bool neq(const StrBlobPtr& lhs,const StrBlobPtr& rhs) {
return !eq(lhs,rhs);
}
#endif

测试

test.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include "my_StrBlob.h"

using namespace std;

int main() {
StrBlob b1;
{
StrBlob b2 = {"a","an","the"};
b1 = b2;
b2.push_back("about");
cout << "b2.size() = " << b2.size() << endl;
cout << "b2.front() = " << b2.front() << " b2.end() = " << b2.back() << endl;
}
cout << "b1.size() = " << b1.size() << endl;
cout << "b1.front() = " << b1.front() << " b1.back() = " << b1.back() << endl;


StrBlob b3 = b1;
b3.push_back("next");
cout << "b3.size() = " << b3.size() << endl;
cout << "b3.front() = " << b3.front() << " b3.back() = " << b3.back() << endl;

cout << "all of b1" << endl;
for (auto it = b1.begin(); neq(it,b1.end()); it.incr())
cout << " it.deref()= " << it.deref() << endl;
return 0;
}