行为像值的类
- 每个类的数据成员都有一份自己的拷贝.不共享数据成员.
#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<>
来管理资源 - 通过普通指针设计引用计数来实现资源管理
引用计数设计原则
- 普通构造创建计数器
- 拷贝构造函数,拷贝数据成员,或者指针本身,同时计数器自增
- 拷贝赋值运算,递减左侧运算对象计数器,递增右侧运算对象计数器,并判断计数器==0
- 析构递减计数器,
==0
回收内存
HasPtr_ptr1.cpp
#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
#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
#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
#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
#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;
}