c++特殊类的设计

设计一个类只能在堆上创建对象

//一个类只能在堆上创建对象(即使用new关键字)
class HeapOnly
{
    publicstatic HeapOnly* createObj()
    {
        return new HeapOnly;
    }
    //将类的所有构造函数设为私有
    //并提供一个静态的方法返回对象的指针或引用
    private:
    	HeapOnly()
            :_a(0)
       {}
   	 HeapOnly(const HeapOnly& h) = delete;
}
int main()
{
    HeapOnly* ptr1 = HeapOnly::CreateObj();
    //HeapOnly copy(*ptr); error
}

设计一个类只能在栈上创建对象

//阻止在堆上通过new创建对象,可以通过删除类的new操作符
//和new[]操作符的重载版本来实现
//1.
class StackOnly
{
    publicstatic StackOnly createObj()
    {
        return  StackOnly();
    }
    private:
    	StackOnly()
       {}
}

//2.new在底层调用的是void*new(size_t size),将它屏蔽掉
class StackOnly
{
public:
    StackOnly() {}
private:
    void* operator new(size_t size) = delete;
    void* operator new[](size_t size) = delete;
    void operator delete(void* p) = delete;
    void operator delete[](void* p) = delete;
}
int main()
{
    StackOnly obj = StackOnly::CreateObj();
    //用1方法能创建,但是不能屏蔽 operator=
    //StackOnly* ptr = new StackOnly(obj); 
    //可以把new屏蔽掉
}

设计一个不能被拷贝

拷贝只会放生在两个场景中:拷贝构造函数以及赋值运算符重载,因此想要让一个类禁止拷贝,只需让该类不能调用拷贝构造函数以及赋值运算符重载即可。

//c98中把这2个函数设置成private
class Copy
{
    Copy(const Copy& c) = delete;
    Copy& operator=(const Copy& s) = delete;
}

设计一个类不能被继承

class NoInherit
{
public:
    static NoInherit GetInstance()
    {
        return NoInherit();
    }
private:
    NoInherit(){}
}

class NoInherit final
{}

设计一个类只能创建一个对象

单例模式

一个类只能创建一个对象,即单例模式,该模式可以保证系统中该类只有一个实例,并提供一个访问它的全局访问点,该实例被所有程序模块共享。

比如在某个服务器程序中,该服务器的配置信息存放在一个文件中,这些配置数据由一个单例对象统一读取,然后服务进程中的其他对象再通过这个单例对象获取这些配置信息,这种方式简化了在复杂环境下的配置管理。

在大多数情况下,单例对象的生命周期与应用程序的生命周期相同,因此不需要显式地回收单例对象。当程序正常结束时,操作系统会自动回收程序所使用的所有资源,包括单例对象所占用的内存。

然而,如果你的单例对象在创建时分配了需要显式释放的资源(如动态分配的内存、文件句柄、数据库连接等),那么在单例对象被销毁时,你需要确保这些资源得到正确的释放。可以考虑在单例对象的析构函数中释放这些资源或者用显示定义垃圾回收类去释放资源。

饿汉模式

如果这个单例对象在多线程高并发环境下频繁使用,性能要求较高,那么显然使用饿汉模式来避免资源竞争,提高响应速度更好。

class Singleton
{
public:
    static Singleton* getInstance()
    {
        return &_instance;
    }
    
private:
  	Singleton(){};
    Singleton(Singleton const&) = delete;
    Singletion& operator=(Singleton const&) = delete;
    
    static Singletion _instance;
}

Singleton Singletion::_instance //在程序入口之前就完成单例对象的初始化

懒汉模式

如果单例对象构造十分耗时或者占用很多资源,比如加载插件, 初始化网络连接,读取文件等等,而有可能该对象程序运行时不会用到,那么也要在程序一开始就进行初始化,就会导致程序启动时非常的缓慢。所以这种情况使用懒汉模式(延迟加载)更好。

class Singleton
{
public:
    static Singleton* getInstance()
    {
       	if(nullptr == _instance)
        {
            _mtx.lock();
            if(nullptr == _instance)
            {
                _instance = new Singleton();
		   }
            _mtx.unlock();
        }
        return _instance;
    }
    //内嵌垃圾回收器
    class CGarbo
    {
     public:
        ~CGarbo()
        {
            if(Singleton::_instance)
                delete Singletion::_instance;
        }
    };
    //定义一个静态成员变量,程序结束时,系统会自动调用它的析构函数从而释放单例对象
    static CGarbo Garbo;
private:
  	Singleton(){};
    Singleton(Singleton const&) = delete;
    Singletion& operator=(Singleton const&) = delete;
    
    static Singletion* _instance;
    static mutex _mtx;
};
Singleton* Singleton::_instance = nullptr;
Singleton::CGarbo Garbo;
mutex Singleton::_mtx;

优缺点对比

懒汉模式(Lazy Initialization)

优点

  1. 延迟加载:在第一次需要使用单例对象时才进行实例化,从而节省了系统资源。如果程序在整个运行过程中都没有使用到单例对象,那么就不会创建该对象,避免了不必要的内存占用。
  2. 灵活性:可以根据实际需求动态地创建和销毁单例对象。

缺点

  1. 线程安全:懒汉模式在并发环境下可能存在线程安全问题。如果不进行同步处理,可能会出现多个线程同时创建单例对象的情况,导致单例模式失效。为了解决这个问题,通常需要在懒汉模式中加入同步机制,但这会增加一定的性能开销。
  2. 性能开销:每次获取单例对象时都需要进行判断和同步操作,这会增加一定的性能开销。特别是在高并发场景下,这种开销可能会更加明显。

饿汉模式(Eager Initialization)

优点

  1. 线程安全:饿汉模式在类加载时就完成了单例对象的创建,因此不存在线程安全问题。
  2. 性能:由于单例对象在类加载时就已经创建完成,因此后续获取单例对象时无需再进行判断和同步操作,性能较高。

缺点

  1. 资源占用:无论程序是否需要使用单例对象,饿汉模式都会在类加载时创建该对象,从而占用一定的系统资源。如果单例对象较大或者初始化耗时较长,这种开销可能会更加明显。
  2. 灵活性:饿汉模式的单例对象在类加载时就已经创建完成,因此无法根据实际需求动态地创建和销毁单例对象。
  • 6
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值