C++ 变量也能像python变量一样使用---再也不用担心内存泄露---让malloc/free,new/delete见鬼去吧

仔细想想,其实所有分配在栈和静态存储区的存储空间都是由一个变量来标识,这是由系统自己管理的内存空间,而堆上分配的空间在每次运行期都是不一样的,也就是不是编译期决定的,所以只能用指针来标识。那么我们是否可以将这种指针标识的内存空间标量化,对象化呢?其实是可以的,事实上python就是这么做的。通过采用引用计数的方式来管理这段内存。我们现在要来实现这样的功能。事先声明,我们实现的都是非线程安全的,需要线程安全可以使用互斥锁。

一、dint的实现

1.设计

dint是int的封装,它是这样一种数据类型:
              1.本质上是int类型,所以我们希望其可以当成int无差别使用,由于int是内置类型,可以隐式转换,所以借助operator()可实现。
              2.只有构造函数会真正产生新的资源消耗,其他操作只是将dint邦定到已有的内存空间。
              3.dint邦定的内存空间是一段结构体空间,其含有int count(引用计数),int data(数据)。
              4.形如a = b;这样的操作发生了如图所示的事件。

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){}
};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;}operator int&(){return p->data;}operator int&() const//convert the const dint{return p->data;}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.
};void test(const dint& i)//covert
{cout<<i<<endl;
}void test2(int &h)
{h = 10000;
}int main()
{dint a(10);dint b(a);dint c = 100;c = a;cout<<a<<endl;if(a < c)cout<<"Success!"<<endl;test(90);int i = 80;test(i);test2(a);cout<<a<<endl;}

一个解决方案是重载“*“和“->“操作符,那么我们就无法实现python那种调用效果了。但是仍然能够很好的实现内存管理。另一个解决方案是制造一个调用句柄如self()函数。个人比较喜欢self函数。一个解决方案是重载“*“和“->“操作符,那么我们就无法实现python那种调用效果了。但是仍然能够很好的实现内存管理。另一个解决方案是制造一个调用句柄如self()函数。个人比较喜欢self函数。一个解决方案是重载“*“和“->“操作符,那么我们就无法实现python那种调用效果了。但是仍然能够很好的实现内存管理。另一个解决方案是制造一个调用句柄如self()函数。个人比较喜欢self函数。

3.总结

这套方案的好处在于,通过将引用计数与结构体内存邦定,而省去了分配表和分配器的开销。不过同样面临一个问题,那就是线程不安全。如果想要安全,那么必须每一个内存块(被分配的)邦定一个互斥锁。还有些问题:

1. 普通的int(静态+栈):无法真正实现将引用传递给dint类型。

2. dint类型的可以实现传递给int的引用。

3. 也即dint可以完全当作int使用,反之则不行。

4. int ,dint间赋值只是简单的值传递。

二、dstring实现

1.设计

dstring是string的封装,它的描述和dint可以类推:有些不同点在于string的operator()不能发生隐式转换,那么将dstring当作string使用必须显示转换,非常麻烦。

一个解决方案是重载“*“和“->“操作符,那么我们就无法实现python那种调用效果了。但是仍然能够很好的实现内存管理。另一个解决方案是制造一个调用句柄如self()函数。个人比较喜欢self函数。

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){}
};class  dstring{
public:dstring(){p = new dtype<string>();}dstring(const string& i){p = new dtype<string>(i);}dstring(const dstring& d){   p = d.p;p->count++;}~dstring(){p->count--;if(0 == p->count){destory();}}dstring& operator=(dstring& d){if(this != &d){int i = --p->count;if(0 == i)destory();p = d.p;p->count++;}return *this;}string& operator*(){return p->data;}const string& operator*() const{return p->data;}string& self(){return p->data;}const string& self() const{return p->data;}operator string&(){return p->data;}operator const string&() const//convert the const dstring{return p->data;}void destory(){cout<<"really delete the p."<<endl;delete p;}
private:dtype<string>* p; //p is nerver be NULL,it is allways bind to a string.
};void test(const dstring& i)//covert
{cout<<*i<<endl;cout<<i.self()<<endl;
}void test2(string &h)
{h = "10000";
}int main()
{dstring a("10");dstring b(a);//dstring c = "100";//c = a;string str = "abc";str = a;cout<<*a<<endl;test(string("90"));string i = "80";test(i);cout<<(*a).size()<<endl;test2(*a);cout<<*a<<endl;cout<<a.self()<<endl;}

dstring& operator=(dstring& d)之所以不用常量引用,是为了禁止将常量指针复制给非常量指针,这完全符合C++的 要求,也是出于安全的考虑。

三、通用版dT实现

1.设计

对于内置类型,可以通过operator()实现封装类型直接当成基础类型来使用,而类类型的话,我们需要通过重载"*"/"->",或者实现"self()"来达到目的。由于我们此处的设计是值语义的使用封装类型,如果使用"*","->"就会是指针语义,那么这样就更接近于智能指针。我个人倾向于使用self()函数,当然a.self().Fuc()这样的调用也过于冗长,我们需要一个使用起来更简洁的方式,函数U:

template<class T>
typenameT::value_type& U(T& t)
{return t.self();
}template <class T>
const typename T::value_type& U(const T& t)
{return t.self();
}

那么我们就可以这样使用a了: U(a).Fuc()     (Fuc()泛指函数)

还有一个需要注意的地方,由于const类型对象只能调用const版本的函数,那么operator(),"*","->","self()"

2.实现

代码:

#include<iostream>
#include<string>
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  Obj_ptr{
public:
typedef T value_type;
public:Obj_ptr(){p = new dtype<T>();}Obj_ptr(const T& i){p = new dtype<T>(i);}Obj_ptr(const Obj_ptr& d){    p = d.p;p->count++;}~Obj_ptr(){p->count--;if(0 == p->count){destory();}}Obj_ptr& operator=(Obj_ptr& d){if(this != &d){int i = --p->count;if(0 == i)destory();p = d.p;p->count++;}return *this;}T& operator*(){return p->data;}const T& operator*() const{return p->data;}T& self(){return p->data;}const T& self() const{return p->data;}operator T&(){return p->data;}operator T&() const//convert the const Obj_ptr{return p->data;}void destory(){cout<<"really delete the p."<<endl;delete p;}
private:dtype<T>* p; //p is nerver be NULL,it is allways bind to a T.
};void test(const Obj_ptr<string>& i)//covert
{//cout<<i<<endl;
}void test2(string &h)
{h = "Hello Test.";
}
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();
}int main()
{Obj_ptr<string> a(string("Hello Bosch."));Obj_ptr<string> b(a);Obj_ptr<string> c = string("Hello youjin.");c = a;cout<<a.self()<<endl;test(string("Hello China."));test2(a);//cout<<a<<endl;cout<<a.self()<<endl;cout<<U(a)<<endl;const Obj_ptr<string> ca(string("Hello Bosch."));cout<<ca.self()<<endl;cout<<U(ca)<<endl;
}

该方法的一个特点就是除了构造函数会生成真正意义上的新变量之外,其他操作都只是指针复制等操作。只会改变也有内存的引用计数。

根据C++11的特性我们还能简化创建变量的代码,设置一个创建函数C:

template<class T>
Obj_ptr<T>& C()
{return  Obj_ptr<T>();
}template<class T>
Obj_ptr<T>& C(const T&t)
{return  Obj_ptr<T>(t);
}template<class T>
Obj_ptr<T>& C(const Obj_ptr<T> &t)
{return  Obj_ptr<T>(t);
}调用方式:1.   auto a = C<string>();2.   auto b = C(string("Hello Bosch."));3.   auto c = C(b);

四、总结

对C++11还不是很了解,但是据说非常强大也许等我看完就可以改进该方案了。该方案的思想是把变量视为两类,一类静态+栈空间,一类堆空间。我们要做的是将对空间的内存分配和销毁对用户透明,不鼓励程序员直接参与malloc/free,new/delete的调用。程序员不需要了解内存的分配情况。
     进一步探讨祥见:C++ 实现Python变量续

C++实现Python变量相关推荐

  1. Python变量类型(l整型,长整形,浮点型,复数,列表,元组,字典)学习

    #coding=utf-8 __author__ = 'Administrator'#Python变量类型#Python数字,python支持四种不同的数据类型 int整型 long长整型 float ...

  2. Python变量作用域问题

    本文最后更新于2018-6-20,可能会因为没有更新而失效.如已失效或需要修正,请联系我! 今天在用Python写程序时突然想起了Python变量作用域的问题,代码如下: def run():glob ...

  3. python变量类型之间转换_Python变量赋值类型转换

    原博文 2018-01-22 22:05 − 1.Python定义变量 1 name = cross10 2 print('name=',name) 打印结果: name=cross10 2.Pyth ...

  4. 关于python变量使用_Python 基础知识关于变量的定义使用

    转自:https://www.cnblogs.com/manongajie/p/12736991.html 1 python 变量概述 变量,英文叫做 variable. 从形式上看,每个变量都拥有独 ...

  5. python变量详解_Python 变量详解[学习 Python 必备基础知识][看此一篇就够了]

    您的"关注"和"点赞",是信任,是认可,是支持,是动力...... 如意见相佐,可留言. 本人必将竭尽全力试图做到准确和全面,终其一生进行修改补充更新. 1 P ...

  6. python变量需要声明吗_python中可以声明变量类型吗

    变量(variable)是Python语言中一个非常重要的概念.变量的主要作用就是为Python程序中的某个值起一个名字.类似于"张三"."李四"." ...

  7. python变量类型-Python 变量类型详解

    变量存储在内存中的值.这就意味着在创建变量时会在内存中开辟一个空间. 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中. 因此,变量可以指定不同的数据类型,这些变量可以存储整 ...

  8. python变量类型-【干货】Python基础语法之变量类型

    原标题:[干货]Python基础语法之变量类型 还没关注? 01 Python编码 Python中默认的编码格式是 ASCII 格式,在没修改编码格式时无法正确打印汉字,所以在读取中文时会报错. 解决 ...

  9. python 类-Python 变量类型

    Python 变量类型 变量存储在内存中的值,这就意味着在创建变量时会在内存中开辟一个空间. 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中. 因此,变量可以指定不同的数据 ...

  10. python变量类型-Python-变量类型

    1.Python变量类型 变量存储在内存中的值.这就意味着在创建变量时会在内存中开辟一个空间. 基于变量的数据类型,解释器会分配指定内存,并决定什么数据可以被存储在内存中. 因此,变量可以指定不同的数 ...

最新文章

  1. NR 5G NG-AP(NG接口)介绍
  2. python list 去重_Python中对列表list去重
  3. 洛谷P2835 刻录光盘
  4. 在让元宇宙“圆梦”这条路上,交互技术卡在哪里了?
  5. matlab 实验6 高层绘图操作,实验06_高层绘图操作(第5章).doc
  6. numpy的基本使用2
  7. Python 中的 if __name__ == '__main__' 该如何理解
  8. 手机音视频应用开发(专注于Symbian、iPhone、Android等跨平台音视频应用开发方案)
  9. java创建线程哪种方法最好_Java创建线程的三种方法比较
  10. c++之std::distance()函数
  11. NLTK学习笔记(六):利用机器学习进行文本分类
  12. 问题解决办法:pip tensorrt成功,PyCharm import出错
  13. 分层架构中各层之间关系如何界定,期待大家来讨论
  14. 虚拟税务ukey托管服务器,税务Ukey托管来啦,给它一个家!企业开票更方便
  15. c语言水文水资源,长江中游水文网
  16. zimbra更换服务器域名
  17. 算法优化:旋转对称图最优解法及思路分享(几乎最优)
  18. CSDN的密码修改流程比之前好多了
  19. matlab两个图共用一个x轴_Matlab绘制多x轴和多y轴图(双x双y轴/单x双y轴/双x单y轴图等),及坐标轴参数汇总...
  20. 工商名人堂 爱德华·约翰逊二世---富达基金的崛起(转载自新浪)

热门文章

  1. Android Multimedia Framework overview(多媒体框架概述)--base on jellybean(一)
  2. 微信企业号开发实例源码
  3. 【索引分类】位图索引
  4. ios swift 纯代码设置UITableViewCell的style
  5. js时间分割——主要用途——租赁合同时间计算(两种时间分割方式,可以按月,季,年分割)
  6. 统计学 分布篇 - Binomial Distribution(二项分布)
  7. 解决win10/Office2016/Onedrive/上载中心经常冲突的问题
  8. 4、数据库服务的启动与登录
  9. 关于4G转wifi路由器模块与4G转有线模块的原理
  10. 网上书店平台---设计活动