本文主要是介绍(P57)面向对象版表达式计算器:单例模式与auto_ptr,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
文章目录
- 1.auto_ptr在单例模式中的应用
1.auto_ptr在单例模式中的应用
- eg:P57\01.cpp
#include <iostream>
#include <memory>
using namespace std;//单例模式是保证一个类在一个程序中只有一个对象,一个实例
//实现单例模式的关键点是:对象禁止拷贝(只需将拷贝构造函数与等号运算符声明为私有的,且并提供它的实现,这样的话,编译会报错),此外将
//构造函数声明为私有的,防止外部任意构造对象,所以需要提供一个接口ingleton::GetInstance();让外部得到这样一个对象
//因为无法通过对象调用成员函数,所以只能通过类调用成员函数,所以将GetInstance声明为static,此外,不论调用多少次GetInstance,返回的是同一个对象
//否则一个程序就有多个对象的拷贝
class Singleton
{
public://GetInstance成员函数可以访问Singleton私有的构造函数static Singleton* GetInstance(){if (instacne_ == NULL){instacne_ = new Singleton;//new:创建一个类的实例}return instacne_;}~Singleton(){cout<<"~Singleton ..."<<endl;}
private://禁止拷贝就是将拷贝构造函数,等号运算符声明为私有的,就可以保证不进行拷贝构造,也不能赋值//禁止拷贝1:禁止调用拷贝构造函数//将拷贝构造函数声明为私有的,且不提供她的实现Singleton(const Singleton& other);//禁止拷贝2://将赋值操作声明为私有的,禁止赋值操作Singleton& operator=(const Singleton& other);//将构造函数声明为私有的,在main函数中就不能调用构造函数Singleton(){cout<<"Singleton ..."<<endl;}//解决办法是使用智能指针,当智能指针生命周期结束的时候,会自动调用析构函数,从而释放指针所持有(指向)的资源//所以智能指针能用在单例模式中,对资源进行释放static Singleton* instacne_;//仅仅声明,这是裸指针,用智能指针管理// static shared_ptr<Singleton> instacne_;//当整个程序结束时,静态对象也会被销毁,就会调用这个shared_ptr类的析构函数,析构就会将其持有的指针资源进行释放
};Singleton* Singleton::instacne_;//定义性的说明int main(void)
{//Singleton s1;//Singleton s2;//不论调用几次GetInstance,总是返回同一个对象,同一个实例//如何验证他们是同一个实例?只需查看s1和s2指针所指向的地址是否一致Singleton* s1 = Singleton::GetInstance();Singleton* s2 = Singleton::GetInstance();//Singleton s3(*s1); // 调用拷贝构造函数//s4=s2return 0;
}
-
测试:new Singleton这个对象未被销毁,析构函数未调用。这个指针static Singleton* instacne_;未被销毁
-
eg:P57\01_share_ptr.cpp
#include <iostream>
#include <memory>
using namespace std;//单例模式是保证一个类在一个程序中只有一个对象,一个实例
//实现单例模式的关键点是:对象禁止拷贝(只需将拷贝构造函数与等号运算符声明为私有的,且并提供它的实现,这样的话,编译会报错),此外将
//构造函数声明为私有的,防止外部任意构造对象,所以需要提供一个接口ingleton::GetInstance();让外部得到这样一个对象
//因为无法通过对象调用成员函数,所以只能通过类调用成员函数,所以将GetInstance声明为static,此外,不论调用多少次GetInstance,返回的是同一个对象
//否则一个程序就有多个对象的拷贝
class Singleton
{
public://GetInstance成员函数可以访问Singleton私有的构造函数static Singleton* GetInstance(){// if (instacne_ == NULL)// {// instacne_ = new Singleton;//new:创建一个类的实例// }// return instacne_;//get()方法返回原生指针,但没有释放所有权,release()方法会释放所有权if (!instacne_.get())){instacne_ = auto_ptr<Singleton>(new Singleton);//智能指针的所有权转移给了instacne_,instacne_持有了new Singleton所分配的内存资源}return instacne_.get();}~Singleton(){cout<<"~Singleton ..."<<endl;}
private://禁止拷贝就是将拷贝构造函数,等号运算符声明为私有的,就可以保证不进行拷贝构造,也不能赋值//禁止拷贝1:禁止调用拷贝构造函数//将拷贝构造函数声明为私有的,且不提供她的实现Singleton(const Singleton& other);//禁止拷贝2://将赋值操作声明为私有的,禁止赋值操作Singleton& operator=(const Singleton& other);//将构造函数声明为私有的,在main函数中就不能调用构造函数Singleton(){cout<<"Singleton ..."<<endl;}//解决办法是使用智能指针,当智能指针生命周期结束的时候,会自动调用析构函数,从而释放指针所持有(指向)的资源//所以智能指针能用在单例模式中,对资源进行释放// static Singleton* instacne_;//仅仅声明,这是裸指针,用智能指针管理static shared_ptr<Singleton> instacne_;//当整个程序结束时,静态对象也会被销毁,就会调用这个shared_ptr类的析构函数,析构就会将其持有的指针资源进行释放
};// Singleton* Singleton::instacne_;//定义性的说明
shared_ptr<Singleton> Singleton::instacne_;int main(void)
{//Singleton s1;//Singleton s2;//不论调用几次GetInstance,总是返回同一个对象,同一个实例//如何验证他们是同一个实例?只需查看s1和s2指针所指向的地址是否一致Singleton* s1 = Singleton::GetInstance();Singleton* s2 = Singleton::GetInstance();//Singleton s3(*s1); // 调用拷贝构造函数//s4=s2return 0;
}
-
测试:析构函数调用了,说明new Singleton这块资源就能够自动释放了
-
eg:P57\02.cpp
#include <iostream>
#include <memory>
using namespace std;//为什么Noncopyable类是禁止拷贝的?
//(1)【采用】禁止对象拷贝的eg演示
//Noncopyable不能构造对象,因为构造对象没意义,仅仅用来继承
class Noncopyable
{
protected:Noncopyable() {};~Noncopyable() {};
private:Noncopyable(const Noncopyable&);const Noncopyable& operator=(const Noncopyable&);
};//这里继承方式是private的,why?
//这里仅仅是继承它的实现,是继承它的实现,而不是继承它的接口,所以是实现继承,而不是接口继承
class Parent : private Noncopyable
{};//Parent是禁止拷贝的,其子类Child也是禁止拷贝的,因为它也继承了Noncopyable的实现
class Child : public Parent
{};int main(void)
{Parent p1;Parent p2(p1);//要调用Parent拷贝构造函数,Parent构造函数又调用Noncopyable的拷贝构造函数//基类的私有成员在派生类中是不能被访问的,所以编译会失败,即使能访问,基类也没//给出实现,同样也会出错Child c1;Child c2(c1);return 0;
}
-
测试:也是禁止拷贝的
-
eg:P57\03.cpp
#include <iostream>
#include <memory>
using namespace std;//为什么Noncopyable类是禁止拷贝的?
//(1)【采用】禁止对象拷贝的eg演示
//Noncopyable不能构造对象,因为构造对象没意义,仅仅用来继承
class Noncopyable
{
protected:Noncopyable() {};~Noncopyable() {};
private:Noncopyable(const Noncopyable&);const Noncopyable& operator=(const Noncopyable&);
};//这里继承方式是private的,why?
//这里仅仅是继承它的实现,是继承它的实现,而不是继承它的接口,所以是实现继承,而不是接口继承
class Parent : private Noncopyable
{
public://构造函数会调用基类的构造函数,即使没有写出Parent(): Noncopyable(),也是会自动调用的Parent()//若基类没有默认构造函数,那么在子类的成员函数列表中给出基类构造函数的调用{}//拷贝构造函数会调用基类的拷贝构造函数,但是只有Parent(const Parent& other) : Noncopyable(other)这么去写//才会调用基类的拷贝构造函数的Parent(const Parent& other) : Noncopyable(other){}
};//Parent是禁止拷贝的,其子类Child也是禁止拷贝的,因为它也继承了Noncopyable的实现
class Child : public Parent
{};int main(void)
{Parent p1;//调用构造函数//调用拷贝构造函数,如果这么写:Parent(const Parent& other){},//Parent中实现了拷贝构造函数,是不会调用基类的拷贝构造函数,那么私有的Noncopyable(const Noncopyable&);这个限制就不生效了Parent p2(p1);//要调用Parent拷贝构造函数,Parent构造函数又调用Noncopyable的拷贝构造函数//基类的私有成员在派生类中是不能被访问的,所以编译会失败,即使能访问,基类也没//给出实现,同样也会出错// Child c1;// Child c2(c1);return 0;
}
- 测试:
- eg:P57\04.cpp
#include <iostream>
using namespace std;//用宏来实现计算某个变量的大小
//sizeof_v
//&x+1,x变量的地址+1,也就是偏移了1个元素的地址,如果元素是4个字节就偏移4个字节
//&x+1 - &x,地址相减,实际上都是指针类型,两个指针相减得到的是他们之间的偏移量,相隔几个元素
//char*类型的地址相隔几个元素就是相隔几个字节
#define sizeof_v(x) (char*)(&x+1) - (char*)&x//使用宏来计算某个类型的大小
//sizeof_t
//((t*)0+1),t*的指针类型,偏移+1,就是偏移一个元素的t类型,得到地址的值刚好等于t类型的大小,但是得到的值类型还是一个指针
//size_t强制转换为整数
#define sizeof_t(t) (sizeof_t)((t*)0+1)//实现一个对齐的宏
//b必须是2的n次方
/*
eg:ALIGN(3, 16)
v=3
b=16
写成二进制:
v=0011
b-1=1111,b减完1以后就是全1的
~(b-1)取反就是全0(v+b-1)就是:
v 0011
b-1 1111
= 10010(v+b-1) & ~(b-1)就是:100100000 将后面4位都抹除掉了
= 10000
10000=16
原理思想:某个数要对齐到16的整数倍,用二进制表示的话,后面就是4个0,0000(用十进制去想,100的十进制后面有2个0)
32的整数倍,后面就是5个0
3对齐到16使用的是向上对齐,3 + 15肯定是超过16,超出的部分抹除掉,对于16而言,就是将低4位都置为0,所以得到的值就是对齐的值ALIGN(0, 16) = 0
ALIGN(16, 16) = 0
100001111
11111
*/
#define ALIGN(v, b) ((v+b-1) & ~(b-1))//为什么要对齐宏ALIGN?因为内存池可能会使用到
/*
比如要分配3个字节,7个字节,9个字节。内存池中的内存块大小是规则的,规则的不容易产生内存碎片。(不规则的物品放在箱子里面会产生空隙或者内存碎片)
要分配内存就无法得到连续的空间,就会被浪费掉。
内存块可以是4K,16K大小的块,32K大小的块。
如果申请内存<=4K,就对齐到4K,保证申请的内存总是4K
如果是4K<内存<=16K,就对齐到16K
如果是16K<内存<=32K,就对齐到32K
采用分级的机制实现内存池
*/class Empty
{};int main(void)
{Empty e;int n;// cout << sizeof(e)<<endl;// cout<<sizeof(Empty)<<endl;//空类的大小是一个字节cout<<sizeof_v(e)<<endl;cout<<sizeof_v(n)<<endl;cout<<sizeof_t(Empty)<<endl;cout<<sizeof_t(int)<<endl;//3对齐到16的整数倍,应该是16cout<<ALLGN(3,16)<<endl;//应该是32cout<<ALLGN(31,16)<<endl;//应该是0cout<<ALLGN(0,16)<<endl;//应该是8192cout<<ALLGN(4198,4096)<<endl;return 0;
}
- 测试:
这篇关于(P57)面向对象版表达式计算器:单例模式与auto_ptr的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!