您的位置:首页 > 编程语言 > C语言/C++

c++学习笔记--行为像指针的类

2017-11-09 21:36 232 查看
行为像指针的类:

class HasPtr
{
public:
HasPtr(const std::string &str = std::string()) :
ps(new std::string(str)), i(0), use(new std::size_t(1)) {}
HasPtr(const HasPtr &obj) :
ps(new std::string(*obj.ps)), i(obj.i), use(obj.use) { ++*use;}
HasPtr &operator=(const HasPtr &obj);
~HasPtr();
std::string get() { return *ps; }
std::size_t get_use() { return *use; }
private:
std::size_t *use;
std::string *ps;
int i;
};


1)对于行为想指针的类,类的对象在拷贝构造或赋值之后。原对象和新对象都应该共享同一块内存。首先要解决的问题是:当一个对象被销毁的时候,如果这个对象所指向的内存还有其他对象指向。这个时候析构函数不能单方面释放那一块共享的内存,必须要在没有其它对象指向的时候才能释放那快内存。

2)要解决这个问题,就需要像智能指针那样使用引用计数。记录着某一块内存当前有几个对象指向它,在最后一个对象指向它,而且这个对象即将要被销毁时。就由这个对象的析构函数将这个内存释放。

3)为了达到引用计数的目的,每个对象被创建的时候都会为它创造一个计数器。并且所有由这个拷贝构造或者赋值得来的对象都会包含这个计数器,每拷贝构造(或赋值)一个对象就递增这个计数器。每销毁指向那块共享内存的对象,就递减计数器。当计数器为0时,就由最后一个指向这块内存的对象负责释放它。

首先是这个类的数据成员,包含一个计数器指针和一个指向共享内存的指针。

private:
std::size_t *use; //计数器
std::string *ps; //指向共享内存的指针
int i;

默认构造函数和拷贝构造函数

<
4000
/span>

HasPtr(const std::string &str = std::string()) :				//构造一个对象的时候为其分配一块共享内存,和一块作为
ps(new std::string(str)), i(0), use(new std::size_t(1)) {}  //计数器的内存,初始值为1,表示当前有一个对象指向这块内存

HasPtr(const HasPtr &obj) :                                         //拷贝构造一个对象,只拷贝指针本身,而不是拷贝指针指向的对象
ps(new std::string(*obj.ps)), i(obj.i), use(obj.use) { ++*use;} //这样才能让两个对象同时指向一块内存。同理计数器指针也是一样
//并且拷贝之后要递增计数器,表示当前多了一个指向它的对象


拷贝赋值运算符

1)拷贝赋值运算符通常会做类似析构函数和拷贝构造函数的工作,也就是递增右侧对象的引用计数,递减左侧对像的引用计数。如果左侧对象的引用计数为0,就是放它所指向的内存。

2)还需要注意的是,要正确处理自赋值的情况。所以要先递增右侧的引用计数,再递减左侧的引用计数。这样即使是自赋值也能正确处理。如果是先递减左侧引用计数,再递增右侧引用计数。在左右对象都是同一个对象的情况下,就会有可能释放了对象指向的资源,这个时候再赋值的话,就是指向一个块已经被释放的内存,发生错误。

HasPtr &HasPtr::operator=(const HasPtr &obj)
{
++*obj.use; //递增右侧对象的引用计数

if (--*use == 0){ //递减左侧对象的引用计数,如果引用计数为0,就释放内存
delete ps;
delete use;
}

i = obj.i;
ps = obj.ps;
use = obj.use;

return *this;
}


最后是析构函数,它检查销毁一个对象前,它递减引用计数后是否为0。如果是,就释放共享内存和计数器

(析构函数是先执行函数体,再执行析构操作。而构造函数是:先执行初始化列表,再执行函数体。二者执行顺序相仿)

HasPtr::~HasPtr()
{
if (--*use == 0){
delete ps;
delete use;
}
}


测试代码

#include <iostream>
#include <string>
#include "behavior_like_pointer_class.h"
using namespace std;

void fun(HasPtr &obj)
{
string str;

cout << "enter string: ";
cin >> str;
HasPtr one(str);
obj = one;
cout << "use: " << one.get_use() << endl;
}

int main()
{
HasPtr obj;
fun(obj);
cout << obj.get() << endl;
cout << obj.get_use() << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: