c++学习笔记--行为像指针的类
2017-11-09 21:36
232 查看
行为像指针的类:
1)对于行为想指针的类,类的对象在拷贝构造或赋值之后。原对象和新对象都应该共享同一块内存。首先要解决的问题是:当一个对象被销毁的时候,如果这个对象所指向的内存还有其他对象指向。这个时候析构函数不能单方面释放那一块共享的内存,必须要在没有其它对象指向的时候才能释放那快内存。
2)要解决这个问题,就需要像智能指针那样使用引用计数。记录着某一块内存当前有几个对象指向它,在最后一个对象指向它,而且这个对象即将要被销毁时。就由这个对象的析构函数将这个内存释放。
3)为了达到引用计数的目的,每个对象被创建的时候都会为它创造一个计数器。并且所有由这个拷贝构造或者赋值得来的对象都会包含这个计数器,每拷贝构造(或赋值)一个对象就递增这个计数器。每销毁指向那块共享内存的对象,就递减计数器。当计数器为0时,就由最后一个指向这块内存的对象负责释放它。
首先是这个类的数据成员,包含一个计数器指针和一个指向共享内存的指针。
默认构造函数和拷贝构造函数
<
4000
/span>
拷贝赋值运算符
1)拷贝赋值运算符通常会做类似析构函数和拷贝构造函数的工作,也就是递增右侧对象的引用计数,递减左侧对像的引用计数。如果左侧对象的引用计数为0,就是放它所指向的内存。
2)还需要注意的是,要正确处理自赋值的情况。所以要先递增右侧的引用计数,再递减左侧的引用计数。这样即使是自赋值也能正确处理。如果是先递减左侧引用计数,再递增右侧引用计数。在左右对象都是同一个对象的情况下,就会有可能释放了对象指向的资源,这个时候再赋值的话,就是指向一个块已经被释放的内存,发生错误。
最后是析构函数,它检查销毁一个对象前,它递减引用计数后是否为0。如果是,就释放共享内存和计数器
(析构函数是先执行函数体,再执行析构操作。而构造函数是:先执行初始化列表,再执行函数体。二者执行顺序相仿)
测试代码
#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;
}
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;
}
相关文章推荐
- C/C++学习笔记-数组和指针
- 【C++学习笔记】指针小结
- [C++学习笔记14]动态创建对象(定义静态方法实现在map查找具体类名对应的创建函数,并返回函数指针,map真是一个万能类)good
- C++学习笔记之八 复合类型---指针、数组和指针运算
- C++学习笔记:C的继承与超越——指针与引用
- C++学习笔记之——c++多态性的类指针总结
- [学习笔记]C和C++中指针的基础知识点(一)
- [学习笔记]C和C++中指针的基础知识点(二)
- C++学习笔记(三)--函数参数,数组函数,指针和const,二维数组函数,递归,函数指针
- C++学习笔记(第六章 指针的应用 字符串 引用 之二)
- C/C++ 学习笔记:指针数组 数组指针 指针函数 函数指针
- VS2010 C++ 学习笔记(六) this指针 const 指针 引用
- C++学习笔记 -- 函数指针与指针函数
- C++学习笔记(一)--整形,std输出,浮点数,数组,字符串,结构,指针,循环
- 【C++ 学习笔记】 异类指针篇
- C/C++中关于地址、指针和引用变量的学习笔记(二) : 数组
- C/C++中关于地址、指针和引用变量的学习笔记(七) : sizeof和typedef
- C++ 学习笔记:原生指针 && 泛型指针 && 智能指针
- C/C++学习笔记:指向指针的指针
- 【C++】学习笔记十一——指针、数组和指针算术