C++实现Python变量续
想问题总是不够全面,一觉醒来突然发现昨天的实现语义不明朗,有点小问题,本来是想实现值语义的,就像a=100,b = a,b = 101.那么b是不会影响a的值得,如果影响了,那就是指针语义了。昨天的设计就是指针语义。
在C/C++中我们一个变量一般会跟固定的内存邦定,在运行期是不会改变的,只有指针会改变。那么我们会认为指针指向的是不同的变量,其实这只不过是一个定势思维。何为变量?这其实是一种概念的东西在C/C++中变量意味着一段固定地址空间的标识。然而在Python中所谓的变量其实就是“指针“(个人理解),例如a = 100.其实就是指针a指向100这个常量,我们关心的只是标识符a的值,但并不关心a存储在那段空间。当改变a的值时,其实只是给它换一个存储空间罢了,如a = 1000.Python所做的并不是改变a所在地址的值,而是给a分配一段新的内存,然后存入1000。这实际上非常合理,我们使用变量的目的是用于计算,计算得核心内容是值,而不是地址。我们关心的只是a和a的值,就像公司只关心你这个人和你的价值,至于你住哪,关我鸟事。C/C++之所以危险就是把计算问题和地址扯上了关系。可能C/C++比较专一吧,认准了a住在1号房间,就死也不放,哪天1号房间住进了b,你还误以为是a,可偏偏C/C++还允许这么2的事情发生。Python在这方面就聪明多了,Python变量比较洒脱,四海为家。一个变量并不代表一段固定的内存。在Python程序中被分配的空间都视为常量,不允许改变。当变量a更新了那你要么找到与你的值对应的空间归队,要么新申请一段内存吧。打个比方,程序中分别分配了如下空间:
空间 0x01 0x02 0x03 0x04 0x05 0x06
语义 1年级 2年级 3年级 4年级 5年级 6年级
a= 1 年级, 那么a指向0x01,那么你就去1年级读书。
a = a+1 = 2 年级, 那么a指向0x02,那么你就去2年级读书。
这种方式比较节约内存,不会出现重复的值。但是需要查表的时间,以时间来换空间,对于现代计算机来说,比较好的做法是新分配一段内存空间来保存新值。但这也有一个问题,那就是这样做的后果是频繁的malloc/free,new/delete那么是否可以解决这一问题呢?有,我们可以借鉴STL的内存分配策略,设置一个内存分配表,和一个内存空闲表,当分配内存失败时,释放掉一些其他空闲表的空间。(这里的分配表是类型分配表)。这样就不需要频繁的释放资源了。
频繁释放资源解释:
a = 100; 0x01
a = 101; 0x02
a=100时,0x01的引用计数是1,当a = 101时,0x01引用计数为0,被销毁,分配0x02。
除了这种处理方案,我们也可以将其改造为智能指针,这就是纯指针语义。但我们的意愿是在程序代码中不允许常规指针的出现。那么就需要有一个分配器,其返回的是智能指针。也就是这种方案指针和分配过程并非邦定。其次,我们可以实现表象是值,但实际是指针语义的功能。好吧下面我们就以dint为例一一实现这三种设计思路(实现的是非线程安全的版本):
一、 值语义dint
1.定义
所谓值语义,就是当我们在使用dint时,表现出来的是值,我们所有的操作都是改变自身的值,而不影响任何其他变量的值,简单来讲, a = b,a = 100,那么b不会跟着改变。这样a = b,获得的是b的值,本意没有抢占b地址的意思,虽然实际上我暂时租用了一会儿。实际上在这种语义上地址不属于任何变量,每个变量都是暂住着。无论是a,b,c关心的只是地址中的数据是否是我想要的,但是并不关系这个数据存在哪里。也没兴趣改变这个地址里的数据。你如果不是我想要的,我就他处找寻去。也即C/C++本身是以地址为中心的。而该语义是以数据为中心的,某段空间里的值在构造期决定,之后就不允许改变。
2.实现
1.频繁释放资源版本
//Version0.1
#include<iostream>
using namespace std;
template<class T>
struct dtype//none thread security
{
int count;
T data;
dtype():count(1){}
dtype(const T& t):count(1),data(t){}
};
class dint{
public:
dint()
{
p = new dtype<int>();
}
dint(const int& i)
{
p = new dtype<int>(i);
}
dint(const dint& d)
{
p = d.p;
p->count++;
}
~dint()
{
p->count--;
if(0 == p->count)
{
destory();
}
}
dint& operator=(dint& d)
{
if(this != &d)
{
int i = --p->count;
if(0 == i)destory();
p = d.p;
p->count++;
}
return *this;
}
dint& operator=(const int& d)
{
int i = --p->count;
if(0 == i)destory();
p = new dtype<int>(d);
return *this;
}
operator int&()
{
return p->data;
}
operator int&() const//convert the const dint
{
return p->data;
}
dint& operator++()
{
int data = p->data;
int i = --p->count;
if(0 == i)destory();
p = new dtype<int>(data+1);
return *this;
}
dint operator++(int)
{
dint tmp(*this);
int data = p->data;
int i = --p->count;
if(0 == i)destory();
p = new dtype<int>(data+1);
return tmp;
}
dint& operator--()
{
int data = p->data;
int i = --p->count;
if(0 == i)destory();
p = new dtype<int>(data-1);
return *this;
}
dint operator--(int)
{
dint tmp(*this);
int data = p->data;
int i = --p->count;
if(0 == i)destory();
p = new dtype<int>(data-1);
return tmp;
}
void destory()
{
cout<<"really delete the p."<<endl;
delete p;
}
private:
dtype<int>* p; //p is nerver be NULL,it is allways bind to a int.
};
2. 空闲表版本
//Version0.2
#include<iostream>
using namespace std;
template<class T>
struct dtype//none thread security
{
int count;
T data;
dtype():count(1){}
dtype(const T& t):count(1),data(t){}
};
template<class T>
struct node{
dtype<T> *p;
struct node* next;
node():next(NULL)
{
p = new dtype<T>();
}
~node()
{
delete p;
}
void set(const T& t)
{
p->data = t;
}
void AddUseCount()
{
p->count++;
}
void SubUseCount()
{
p->count--;
}
bool IsCount0()
{
return !(p->count);
}
T& GetData()
{
return p->data;
}
};
template<class T>
class Alloctor{
public:
Alloctor():ListHead(NULL),ListTail(NULL),len(0)
{
Malloc(10);
}
~Alloctor()
{
while(len)
{
cout<<"~Alloctor()"<<endl;
delete pop();
}
}
node<T>* Construct()
{
if(ListHead == NULL && ListTail == NULL)//can be delete
{
Malloc(10);
}
else if(ListHead == ListTail)
{
Malloc(10);
}
//get the element on head.
return pop();
}
node<T>* Construct(const T& t)
{
if(ListHead == NULL && ListTail == NULL)//can be delete
{
Malloc(10);
}
else if(ListHead == ListTail)
{
Malloc(10);
}
//get the element on head.
node<T>* n = pop();
n->set(t);
return n;
}
bool destory(node<T>* n)
{
if(len < 100) //add to the tail;
{
cout<<"push to the tail of freeList."<<endl;
push(n);
}
else{ //really delete.
cout<<"really delete the block."<<endl;
delete n;
for(int i = 0;i < 50;i++)
{
delete pop();
}
}
}
protected:
void Malloc(int size)
{
while(size)
{
node<T> *n = new node<T>();
push(n);
size--;
}
}
node<T>* pop()
{
node<T> * n = ListHead;
ListHead = ListHead->next;
len--;
return n;
}
bool push(node<T>* n)
{
if(ListHead == NULL && ListTail == NULL)
{
ListHead = ListTail = n;
}
else{
ListTail->next = n;
ListTail = n;
}
len++;
}
private:
node<T>* ListHead;
node<T>* ListTail;
int len;
};
class dint{
public:
dint()
{
block = alloc.Construct();
}
dint(const int& i)
{
block = alloc.Construct(i);
}
dint(const dint& d)
{
block = d.block;
block->AddUseCount();
}
~dint()
{
block->SubUseCount();
if(true == block->IsCount0())
{
destory();
}
}
dint& operator=(dint& d)
{
if(this != &d)
{
block->SubUseCount();
if(true == block->IsCount0())destory();
block = d.block;
block->AddUseCount();
}
return *this;
}
dint& operator=(const int& d)
{
block->SubUseCount();
if(true == block->IsCount0())destory();
block = alloc.Construct(d);
return *this;
}
operator int&()
{
return block->GetData();
}
operator int&() const//convert the const dint
{
return block->GetData();
}
dint& operator++()
{
int data = block->GetData();
block->SubUseCount();
if(true == block->IsCount0())destory();
block = alloc.Construct(data+1);
return *this;
}
dint operator++(int)
{
dint tmp(*this);
int data = block->GetData();
block->SubUseCount();
if(true == block->IsCount0())destory();
block = alloc.Construct(data+1);
return tmp;
}
dint& operator--()
{
int data = block->GetData();
block->SubUseCount();
if(true == block->IsCount0())destory();
block = alloc.Construct(data-1);
return *this;
}
dint operator--(int)
{
dint tmp(*this);
int data = block->GetData();
block->SubUseCount();
if(true == block->IsCount0())destory();
block = alloc.Construct(data-1);
return tmp;
}
void destory()
{
cout<<"ask alloc for delete."<<endl;
alloc.destory(block);
}
private:
node<int>* block; //p is nerver be NULL,it is allways bind to a int.
static Alloctor<int> alloc;
};
Alloctor<int> dint::alloc = Alloctor<int>();
3.通用版本(含空闲表)
//Version0.3
#include<iostream>
#include<vector>
#include<cstdlib>
#include<stdio.h>
using namespace std;
template<class T>
struct dtype//none thread security
{
int count;
T data;
dtype():count(1){}
dtype(const T& t):count(1),data(t){}
};
template<class T>
struct node{
dtype<T> *p;
struct node* next;
node():next(NULL)
{
p = new dtype<T>();
}
~node()
{
delete p;
}
void set(const T& t)
{
p->data = t;
}
void AddUseCount()
{
p->count++;
}
void SubUseCount()
{
p->count--;
}
bool IsCount0()
{
return !(p->count);
}
T& GetData()
{
return p->data;
}
};
template<class T>
class Alloctor{
public:
Alloctor():ListHead(NULL),ListTail(NULL),len(0)
{
Malloc(10);
}
~Alloctor()
{
while(len)
{
cout<<"~Alloctor()"<<endl;
delete pop();
}
}
node<T>* Construct()
{
if(ListHead == NULL && ListTail == NULL)//can be delete
{
Malloc(10);
}
else if(ListHead == ListTail)
{
Malloc(10);
}
//get the element on head.
return pop();
}
node<T>* Construct(const T& t)
{
if(ListHead == NULL && ListTail == NULL)//can be delete
{
Malloc(10);
}
else if(ListHead == ListTail)
{
Malloc(10);
}
//get the element on head.
node<T>* n = pop();
n->set(t);
return n;
}
bool destory(node<T>* n)
{
if(len < 100) //add to the tail;
{
cout<<"push to the tail of freeList."<<endl;
push(n);
}
else{ //really delete.
cout<<"really delete the block."<<endl;
delete n;
for(int i = 0;i < 50;i++)
{
delete pop();
}
}
}
protected:
void Malloc(int size)
{
while(size)
{
node<T> *n = new node<T>();
push(n);
size--;
}
}
node<T>* pop()
{
node<T> * n = ListHead;
ListHead = ListHead->next;
len--;
return n;
}
bool push(node<T>* n)
{
if(ListHead == NULL && ListTail == NULL)
{
ListHead = ListTail = n;
}
else{
ListTail->next = n;
ListTail = n;
}
len++;
}
private:
node<T>* ListHead;
node<T>* ListTail;
int len;
};
template<class T>
class PythonC{
public:
typedef T value_type;
public:
PythonC()
{
block = alloc.Construct();
}
PythonC(const T& i)
{
block = alloc.Construct(i);
}
PythonC(const PythonC& d)
{
block = d.block;
block->AddUseCount();
}
~PythonC()
{
block->SubUseCount();
if(true == block->IsCount0())
{
destory();
}
}
PythonC& operator=(PythonC& d)
{
if(this != &d)
{
block->SubUseCount();
if(true == block->IsCount0())destory();
block = d.block;
block->AddUseCount();
}
return *this;
}
PythonC& operator=(const T& d)
{
block->SubUseCount();
if(true == block->IsCount0())destory();
block = alloc.Construct(d);
return *this;
}
operator T&()
{
return block->GetData();
}
operator const T&() const//convert the const PythonC
{
return block->GetData();
}
T& operator*()
{
return block->GetData();
}
const T& operator*() const
{
return block->GetData();
}
T& self()
{
return block->GetData();
}
const T& self() const
{
return block->GetData();
}
friend ostream& operator<<(ostream& os, const PythonC<T>& f)
{
cout<<(f.block)->GetData();
}
protected:
PythonC& operator++();
PythonC operator++(int);
PythonC& operator--();
PythonC operator--(int);
void destory()
{
cout<<"ask alloc for delete."<<endl;
alloc.destory(block);
}
private:
node<T>* block; //p is nerver be NULL,it is allways bind to a int.
static Alloctor<T> alloc;
};
template<class T> Alloctor<T> PythonC<T>::alloc = Alloctor<T>();
template <class T>
typename T::value_type& U(T& t)
{
cout<<"U Function."<<endl;
return t.self();
}
template <class T>
const typename T::value_type& U(const T& t)
{
cout<<"d U Function."<<endl;
return t.self();
}
3.测试
1.Version0.1测试
void test(dint& i)//covert
{
i = 9999;
}
void test2(dint h)
{
h = 888;
}
int main()
{
dint c;
c = 100;
dint a = c;
a = a*a;
cout<<c<<endl;
cout<<a<<endl;
test2(a);
cout<<a<<endl;
test(a);
cout<<a<<endl;
cout<<a++<<endl;
cout<<++a<<endl;
}
2.Version0.2测试
void test(dint& i)//covert
{
i = 9999;
}
void test2(dint h)
{
h = 888;
}
int main()
{
dint c;
c = 100;
dint a = c;
a = a*a;
cout<<c<<endl;
cout<<a<<endl;
test2(a);
cout<<a<<endl;
test(a);
cout<<a<<endl;
cout<<a++<<endl;
cout<<++a<<endl;
}
3.Version0.3测试
class String{
public:
typedef PythonC<char> value_type;
public:
String(){}
void push(const value_type& d)
{
str.push_back(d);
}
friend ostream& operator<<(ostream& os, const String& f)
{
vector<value_type>::const_iterator iter = (f.str).begin();
vector<value_type>::const_iterator End = (f.str).end();
os<<End-iter<<endl;
while(iter != End)
{
os<<*iter++;
}
return os;
}
private:
vector<value_type> str;
};
int main()
{
PythonC<char> c = 'A';
cout<<c<<endl;
String s;
for(int i = 0;i < 10;i++)
{
s.push(c);
}
cout<<s<<endl;
String l = s;
cout<<l<<endl;
PythonC<char> pc = 'B';
l.push(pc);
cout<<s<<endl;
cout<<l<<endl;
}
4.总结
该语义下,传递函数参数和C/C++相同,传递标量会产生临时变量,不会改变传入变量的值。传递引用则不会产生临时变量,会改变传入变量的值。其实改变值同时也伴随着新的空间分配。与定义部分无冲突。但是基于实现的细节,我们必须禁用++,--操作符,或者重载。我们给出的是重载版本,但在通用模板中由于不是所有类型都有++,--操作,所以禁用这两个操作符。事实上我们要把所有操作地址的操作都重载掉。const函数版本是非常有必要的,否则常量就不能正常工作了。这里说的通用版本只是针对内置类型,因为其他类类型及STL的容器类型有许多操作会改变内存,而我们的宗旨是不允许改变内存。然而实现统一的禁用所有改变内存的操作显得不现实。所以目前仅仅实现内置类型的通用版本。虽然这里通用版本实现了“*“操作符,但是由于是值语义所以不建议使用。推荐:self(),U()。实际上内置类型可以隐式类型转换,不需要这些操作亦可。
实现类类型的版本唯一的办法就是所有类的实现都基于我们封装的内置类型。
二、 指针语义dint
1. 定义
所谓指针语义就是改变变量的值实际是改变某个特定内存空间的值,此时dint不代表一个实际的数据,而是表示指向某个数据的智能指针,如dint a;其实a本质上是一个NULL指针。它与内存的分配完全是0耦合的。由于不建议程序员直接使用常规指针(不允许智能指针指向非动态分配的内存空间)。所以需要一个构造器C。dint a = C<dint>(); dint b = a;当改变b时a也会跟着改变的。这就是指针语义,a,b被绑定到同一段内存空间。对a,b的操作意味着对这段内存空间的操作。
2. 实现
1. 无空闲表版本
//Version0.4
#include<iostream>
using namespace std;
template<class T>
struct dtype//none thread security
{
int count;
T data;
dtype():count(1){}
dtype(const T& t):count(1),data(t){}
};
template<class T>
class Alloctor{
public:
Alloctor(){}
~Alloctor(){}
dtype<T>* Construct()
{
return new dtype<T>();
}
dtype<T>* Construct(const T& t)
{
return new dtype<T>(t);
}
};
static Alloctor<int> alloc = Alloctor<int>();
dtype<int>* C()
{
return alloc.Construct();
}
dtype<int>* C(const int& i)
{
return alloc.Construct(i);
}
class dint{
public:
dint():block(NULL){}
dint(dtype<int>* p):block(p){}
dint(const dint& d)
{
block = d.block;
block->count++;
}
~dint()
{
block->count--;
if(0 == block->count)
{
destory();
}
}
dint& operator=(dint& d)
{
if(this != &d)
{
block->count--;
if(0 == block->count)destory();
block = d.block;
block->count++;
}
return *this;
}
dint& operator=(dtype<int>* p)
{
block->count--;
if(0 == block->count)destory();
block = p;
block->count++;
return *this;
}
int& operator*()
{
return block->data;
}
const int& operator*() const
{
return block->data;
}
int* operator->() //can't use in int.
{
return &block->data;
}
const int* operator->() const
{
return &block->data;
}
void destory()
{
cout<<"really delete the p."<<endl;
delete block;
}
private:
dtype<int>* block; //p is nerver be NULL,it is allways bind to a int.
};
2. 空闲表版本
//Version0.5
#include<iostream>
using namespace std;
template<class T>
struct dtype//none thread security
{
int count;
T data;
dtype():count(1){}
dtype(const T& t):count(1),data(t){}
};
template<class T>
struct node{
dtype<T> *p;
struct node* next;
node():next(NULL)
{
p = new dtype<T>();
}
~node()
{
delete p;
}
void set(const T& t)
{
p->data = t;
}
void AddUseCount()
{
p->count++;
}
void SubUseCount()
{
p->count--;
}
bool IsCount0()
{
return !(p->count);
}
T& GetData()
{
return p->data;
}
};
template<class T>
class Alloctor{
public:
Alloctor():ListHead(NULL),ListTail(NULL),len(0)
{
Malloc(10);
}
~Alloctor()
{
while(len)
{
cout<<"~Alloctor()"<<endl;
delete pop();
}
}
node<T>* Construct()
{
if(ListHead == NULL && ListTail == NULL)//can be delete
{
Malloc(10);
}
else if(ListHead == ListTail)
{
Malloc(10);
}
//get the element on head.
return pop();
}
node<T>* Construct(const T& t)
{
if(ListHead == NULL && ListTail == NULL)//can be delete
{
Malloc(10);
}
else if(ListHead == ListTail)
{
Malloc(10);
}
//get the element on head.
node<T>* n = pop();
n->set(t);
return n;
}
bool destory(node<T>* n)
{
if(len < 100) //add to the tail;
{
cout<<"push to the tail of freeList."<<endl;
push(n);
}
else{ //really delete.
cout<<"really delete the block."<<endl;
delete n;
for(int i = 0;i < 50;i++)
{
delete pop();
}
}
}
protected:
void Malloc(int size)
{
while(size)
{
node<T> *n = new node<T>();
push(n);
size--;
}
}
node<T>* pop()
{
node<T> * n = ListHead;
ListHead = ListHead->next;
len--;
return n;
}
bool push(node<T>* n)
{
if(ListHead == NULL && ListTail == NULL)
{
ListHead = ListTail = n;
}
else{
ListTail->next = n;
ListTail = n;
}
len++;
}
private:
node<T>* ListHead;
node<T>* ListTail;
int len;
};
static Alloctor<int> alloc = Alloctor<int>();
node<int>* C()
{
return alloc.Construct();
}
node<int>* C(const int& i)
{
return alloc.Construct(i);
}
class dint{
public:
dint():block(NULL){}
dint(node<int>* p):block(p){}
dint(const dint& d)
{
block = d.block;
block->AddUseCount();
}
~dint()
{
block->SubUseCount();
if(true == block->IsCount0())
{
destory();
}
}
dint& operator=(dint& d)
{
if(this != &d)
{
block->SubUseCount();
if(true == block->IsCount0())destory();
block = d.block;
block->AddUseCount();
}
return *this;
}
dint& operator=(node<int>* p)
{
block->SubUseCount();
if(true == block->IsCount0())destory();
block = p;
block->AddUseCount();
return *this;
}
int& operator*()
{
return block->GetData();
}
const int& operator*() const
{
return block->GetData();
}
void destory()
{
cout<<"ask alloc for delete."<<endl;
alloc.destory(block);
}
private:
node<int>* block; //p is nerver be NULL,it is allways bind to a int.
};
3.通用版(含空闲表)
// Version0.6
#include<iostream>
#include<vector>
using namespace std;
template<class T>
struct dtype//none thread security
{
int count;
T data;
dtype():count(1){}
dtype(const T& t):count(1),data(t){}
};
template<class T>
struct node{
dtype<T> *p;
struct node* next;
node():next(NULL)
{
p = new dtype<T>();
}
~node()
{
delete p;
}
void set(const T& t)
{
p->data = t;
}
void AddUseCount()
{
p->count++;
}
void SubUseCount()
{
p->count--;
}
bool IsCount0()
{
return !(p->count);
}
T& GetData()
{
return p->data;
}
};
template<class T>
class Alloctor{
public:
Alloctor():ListHead(NULL),ListTail(NULL),len(0)
{
Malloc(10);
}
~Alloctor()
{
while(len)
{
cout<<"~Alloctor()"<<endl;
delete pop();
}
}
node<T>* Construct()
{
if(ListHead == NULL && ListTail == NULL)//can be delete
{
Malloc(10);
}
else if(ListHead == ListTail)
{
Malloc(10);
}
//get the element on head.
return pop();
}
node<T>* Construct(const T& t)
{
if(ListHead == NULL && ListTail == NULL)//can be delete
{
Malloc(10);
}
else if(ListHead == ListTail)
{
Malloc(10);
}
//get the element on head.
node<T>* n = pop();
n->set(t);
return n;
}
bool destory(node<T>* n)
{
if(len < 100) //add to the tail;
{
cout<<"push to the tail of freeList."<<endl;
push(n);
}
else{ //really delete.
cout<<"really delete the block."<<endl;
delete n;
for(int i = 0;i < 50;i++)
{
delete pop();
}
}
}
protected:
void Malloc(int size)
{
while(size)
{
node<T> *n = new node<T>();
push(n);
size--;
}
}
node<T>* pop()
{
node<T> * n = ListHead;
ListHead = ListHead->next;
len--;
return n;
}
bool push(node<T>* n)
{
if(ListHead == NULL && ListTail == NULL)
{
ListHead = ListTail = n;
}
else{
ListTail->next = n;
ListTail = n;
}
len++;
}
private:
node<T>* ListHead;
node<T>* ListTail;
int len;
};
template<class T>
class MemManager{
public:
static Alloctor<T> alloc;
};
template<class T> Alloctor<T> MemManager<T>::alloc = Alloctor<T>();
template<class T>
class Obj_ptr{
public:
typedef T value_type;
public:
Obj_ptr():block(NULL){}
Obj_ptr(node<T>* p)
{
block = p;
}
Obj_ptr(const Obj_ptr& d)
{
block = d.block;
block->AddUseCount();
}
~Obj_ptr()
{
block->SubUseCount();
if(true == block->IsCount0())
{
destory();
}
}
Obj_ptr& operator=(Obj_ptr& d)
{
if(this != &d)
{
block->SubUseCount();
if(true == block->IsCount0())destory();
block = d.block;
block->AddUseCount();
}
return *this;
}
T& operator*()
{
return block->GetData();
}
const T& operator*() const
{
return block->GetData();
}
T* operator->()
{
return &(block->GetData());
}
const T* operator->() const
{
return &(block->GetData());
}
protected:
void destory()
{
cout<<"ask alloc for delete."<<endl;
MemManager<T>::alloc.destory(block);
}
private:
node<T>* block; //p is nerver be NULL,it is allways bind to a int.
};
template<class T>
node<T>* C()
{
return MemManager<T>::alloc.Construct();
}
template<class T>
node<T>* C(const T& i)
{
return MemManager<T>::alloc.Construct(i);
}
3. 测试
1.Version0.4测试
void test(dint& i)//covert
{
*i = 9999;
}
void test2(dint h)
{
*h = 888;
}
int main()
{
dint c = C(10);
dint b = c;
dint a = c;
*a = 100;
cout<<*a<<" "<<*b<<" "<<*c<<endl;
*a = *a + 33;
cout<<*a<<" "<<*b<<" "<<*c<<endl;
const dint d = c;
cout<<*d<<endl;
}
2.Version0.5测试
//Version0.5
void test(dint& i)//covert
{
*i = 9999;
}
void test2(dint h)
{
*h = 888;
}
int main()
{
dint c = C(10);
dint b = c;
dint a = c;
*a = 100;
cout<<*a<<" "<<*b<<" "<<*c<<endl;
*a = *a + 33;
cout<<*a<<" "<<*b<<" "<<*c<<endl;
const dint d = c;
cout<<*d<<endl;
}
3.Version0.6测试
//Version0.6
int main()
{
typedef vector<int> Type;
Obj_ptr<Type> s = C<Type>();
s->push_back(100);
cout<<s->empty()<<endl;
cout<<s->size()<<endl;
}
4. 总结
在该语义下,dint完全是一个智能指针,它只能通过"*","->"操作符来访问对象。引用计数和对象绑定虽然带来了空间上的消耗,但是节省了管理内存的时间。
三、 值-指针语义dint
1. 定义
所谓值-指针语义:就是可以以对象的形式来使用指针,彻底抛弃“*“,“->“操作符。但实际上它仍然是指针语义。也需要配合Alloctor来使用,程序员接触到的构造器是C(也可以定义为New/Malloc)。
2. 实现
这里就只给出通用版本了的实现了,分配器其实都是相同的:
1.通用版(含空闲列表)
//Version0.7
#include<iostream>
#include<vector>
using namespace std;
template<class T>
struct dtype//none thread security
{
int count;
T data;
dtype():count(1){}
dtype(const T& t):count(1),data(t){}
};
template<class T>
struct node{
dtype<T> *p;
struct node* next;
node():next(NULL)
{
p = new dtype<T>();
}
~node()
{
delete p;
}
void set(const T& t)
{
p->data = t;
}
void AddUseCount()
{
p->count++;
}
void SubUseCount()
{
p->count--;
}
bool IsCount0()
{
return !(p->count);
}
T& GetData()
{
return p->data;
}
};
template<class T>
class Alloctor{
public:
Alloctor():ListHead(NULL),ListTail(NULL),len(0)
{
Malloc(10);
}
~Alloctor()
{
while(len)
{
cout<<"~Alloctor()"<<endl;
delete pop();
}
}
node<T>* Construct()
{
if(ListHead == NULL && ListTail == NULL)//can be delete
{
Malloc(10);
}
else if(ListHead == ListTail)
{
Malloc(10);
}
//get the element on head.
return pop();
}
node<T>* Construct(const T& t)
{
if(ListHead == NULL && ListTail == NULL)//can be delete
{
Malloc(10);
}
else if(ListHead == ListTail)
{
Malloc(10);
}
//get the element on head.
node<T>* n = pop();
n->set(t);
return n;
}
bool destory(node<T>* n)
{
if(len < 100) //add to the tail;
{
cout<<"push to the tail of freeList."<<endl;
push(n);
}
else{ //really delete.
cout<<"really delete the block."<<endl;
delete n;
for(int i = 0;i < 50;i++)
{
delete pop();
}
}
}
protected:
void Malloc(int size)
{
while(size)
{
node<T> *n = new node<T>();
push(n);
size--;
}
}
node<T>* pop()
{
node<T> * n = ListHead;
ListHead = ListHead->next;
len--;
return n;
}
bool push(node<T>* n)
{
if(ListHead == NULL && ListTail == NULL)
{
ListHead = ListTail = n;
}
else{
ListTail->next = n;
ListTail = n;
}
len++;
}
private:
node<T>* ListHead;
node<T>* ListTail;
int len;
};
template<class T>
class MemManager{
public:
static Alloctor<T> alloc;
};
template<class T> Alloctor<T> MemManager<T>::alloc = Alloctor<T>();
template<class T>
class Obj_ptr{
public:
typedef T value_type;
public:
Obj_ptr():block(NULL){}
Obj_ptr(node<T>* p)
{
block = p;
}
Obj_ptr(const Obj_ptr& d)
{
block = d.block;
block->AddUseCount();
}
~Obj_ptr()
{
block->SubUseCount();
if(true == block->IsCount0())
{
destory();
}
}
Obj_ptr& operator=(Obj_ptr& d)
{
if(this != &d)
{
block->SubUseCount();
if(true == block->IsCount0())destory();
block = d.block;
block->AddUseCount();
}
return *this;
}
operator T&()
{
return block->GetData();
}
operator const T&() const//convert the const Obj_ptr
{
return block->GetData();
}
T& self()
{
return block->GetData();
}
const T& self() const
{
return block->GetData();
}
protected:
void destory()
{
cout<<"ask alloc for delete."<<endl;
MemManager<T>::alloc.destory(block);
}
private:
node<T>* block; //p is nerver be NULL,it is allways bind to a int.
};
template <class T>
typename T::value_type& U(T& t)
{
cout<<"U Function."<<endl;
return t.self();
}
template <class T>
const typename T::value_type& U(const T& t)
{
cout<<"d U Function."<<endl;
return t.self();
}
template<class T>
node<T>* C()
{
return MemManager<T>::alloc.Construct();
}
template<class T>
node<T>* C(const T& i)
{
return MemManager<T>::alloc.Construct(i);
}
3.测试
int main()
{
typedef vector<int> Type;
Obj_ptr<Type> s = C<Type>();
U(s).push_back(100);
cout<<U(s).empty()<<endl;
cout<<U(s).size()<<endl;
}
4.总结
在该语义下我们彻底的摆脱了"*","->"操作符,可以像使用普通对象一样使用指针了,但是我们必须时刻保持指针这个意识,改变某一个值将引起“蝴蝶效应”。