网站建设注册小程序,html5电影网站源码php,可以用tomcat.做网站吗,现在免费的外贸平台有哪些目录 一、了解单例模式前的基础题
1、设计一个类#xff0c;不能被拷贝
2、设计一个类#xff0c;只能在堆上创建对象
3、设计一个类#xff0c;只能在栈上创建对象
4、设计一个类#xff0c;不能被继承
二、单例模式
1、单例模式的概念
2、单例模式的两种实现方式 …
目录 一、了解单例模式前的基础题
1、设计一个类不能被拷贝
2、设计一个类只能在堆上创建对象
3、设计一个类只能在栈上创建对象
4、设计一个类不能被继承
二、单例模式
1、单例模式的概念
2、单例模式的两种实现方式
2.1 懒汉模式实现单例模式
2.2 饿汉模式实现单例模式 一、了解单例模式前的基础题
1、设计一个类不能被拷贝 拷贝只会发生在两个场景中拷贝构造函数以及赋值运算符重载因此 想要让一个类禁止拷贝 只需让该类不能调用拷贝构造函数以及赋值运算符重载即可 。 C98 将拷贝构造函数与赋值运算符重载只声明不定义并且将其访问权限设置为私有即可。 class CopyBan
{// ...private:CopyBan(const CopyBan);CopyBan operator(const CopyBan);//...
}; 原因 1. 设置成私有如果只声明没有设置成 private 用户自己如果在类外定义了就可以不 能禁止拷贝了 2. 只声明不定义不定义是因为该函数根本不会调用定义了其实也没有什么意义不写 反而还简单而且如果定义了就不会防止成员函数内部拷贝了。 C11 C11 扩展 delete 的用法 delete 除了释放 new 申请的资源外如果在默认成员函数后跟上 delete 表示让编译器删除掉该默认成员函数。 class CopyBan
{// ...CopyBan(const CopyBan)delete;CopyBan operator(const CopyBan)delete;//...
}; 2、设计一个类只能在堆上创建对象
思路 创建对象一定调用构造函数或拷贝构造两种禁用方式故先禁掉构造函数私有化构造函数对于拷贝构造下面有两种方式则放在类中的私有下但是怎么在堆上创建对象用一个成员函数GetObj来在堆上创建对象因为类内能访问私有成员中的构造函数类外不可以那为什么要用static修饰GetObj这样就可以用类名::GetObj来访问了而不用创建一个对象才能访问GetObj因为你调用GetObj之前创建的对象一定是在栈上的此外拷贝构造要设置为私有或直接delete即不能使用因为存在你拷贝构造一个栈上的对象的场景即用拷贝构造来创建对象 步骤 1. 将类的构造函数私有拷贝构造声明为delete防止别人调用拷贝在栈上生成对象。 2. 提供一个静态的成员函数在该静态成员函数中完成堆对象的创建 class HeapOnly
{
public:static HeapOnly* GetObj(){//专门用来在堆上创建对象return new HeapOnly;//注意这里是返回HeapOnly指针那只是指针的拷贝//而不是对象的拷贝故不会调用构造函数}//C11:防拷贝拷贝构造函数声明成deleteHeapOnly(const HeapOnly) delete;
private://构造函数私有化HeapOnly(){}//C98防拷贝拷贝构造函数声明为私有//HeapOnly(const HeapOnly);
};int main()
{//HeapOnly hp; //在栈上创建失败HeapOnly* p HeapOnly::GetObj();//成功【创建一个在堆上的对象】std::shared_ptrHeapOnly sp1(HeapOnly::GetObj());std::shared_ptrHeapOnly sp2(HeapOnly::GetObj());//HeapOnly copy(*sp1);//用栈上的对象来拷贝构造copy是不行的故要禁掉拷贝构造return 0;
} 3、设计一个类只能在栈上创建对象 和只能在堆上创建对象思路的唯一区别在于创建的栈的对象需传值返回对象的拷贝要调用拷贝构造函数所以不能禁掉拷贝构造函数 class StackOnly
{
public:static StackOnly CreateObj(){//因为返回个匿名对象传值返回会调用拷贝构造//故不能禁掉拷贝构造return StackOnly();}private:StackOnly(){}
};int main()
{StackOnly obj StackOnly::CreateObj();//StackOnly* ptr3 new StackOnly; //失败
} 下面是有缺陷的代码 下面的代码只是禁掉了在堆区创建数据但是在静态区创建的数据还是无法阻止 //该方案存在一定程度缺陷无法阻止在数据段(静态区)创建对象
class StackOnly
{
public:// 禁掉operator new可以把下面用new 调用拷贝构造申请对象给禁掉void* operator new(size_t size) delete;
};int main()
{StackOnly so;//new分为operator new 构造函数//StackOnly* ptr3 new StackOnly(obj); //失败static StackOnly sso;//在静态区上开辟成功return 0;
} 4、设计一个类不能被继承 C98方式 // C98中构造函数私有化派生类中调不到基类的构造函数。则无法继承
class NonInherit
{
public:static NonInherit GetInstance(){return NonInherit();}
private:NonInherit(){}
}; C11方式 final 关键字 final 修饰类表示该类不能被继承。 class A final
{// ....
}; 二、单例模式 1、单例模式的概念 设计模式 设计模式 Design Pattern 是一套 被反复使用、多数人知晓的、经过分类的、代码设计经验的 总结。为什么会产生设计模式这样的东西呢就像人类历史发展会产生兵法。最开始部落之间打仗时都是人拼人的对砍。后来春秋战国时期七国之间经常打仗就发现打仗也是有 套路的后来孙子就总结出了《孙子兵法》。孙子兵法也是类似。 使用设计模式的目的为了代码可重用性、让代码更容易被他人理解、保证代码可靠性。 设计模式使代码编写真正工程化设计模式是软件工程的基石脉络如同大厦的结构一样。 单例模式 一个类只能创建一个对象即单例模式该模式可以保证系统中该类只有一个实例并提供一个访问它的全局访问点该实例被所有程序模块共享。比如在某个服务器程序中该服务器的配置信息存放在一个文件中这些配置数据由一个单例对象统一读取然后服务进程中的其他对象再通过这个单例对象获取这些配置信息这种方式简化了在复杂环境下的配置管理。 单例模式有两种实现模式懒汉模式和饿汉模式 2、单例模式的两种实现方式
设计一个类只能创建一个对象(单例模式)
那么题目的意思就是保证全局只有一个实例对象
①、单例模式大体结构有缺陷 class Singleton
{
public:static Singleton* GetInstance(){if (_pinst nullptr){//因为是静态成员变量除了第一次为nullptr//再进来不是nullptr了直接返回_pinst即可_pinst new Singleton;}return _pinst;}private:Singleton(){}Singleton(const Singleton s) delete;static Singleton* _pinst;//静态成员的声明
};Singleton* Singleton::_pinst nullptr;//静态成员的定义int main()
{//Singleton s1; //失败//保证获取的对象每次都是同一个cout Singleton::GetInstance() endl;cout Singleton::GetInstance() endl;cout Singleton::GetInstance() endl;//Singleton copy(*Singleton::GetInstance());//无法调用拷贝构造return 0;
}
运行结果 上面代码缺陷是线程安全问题如果两个线程同时要new一个对象即_pinst new Singleton这时就发生错误了我们要的是只有一个对象故引出锁解决 那我们先看看这种错误出现的场景
为了防止线程跑太快而达不到我们想看到错误情况的效果我们用sleep睡眠来辅助 为解决上面的问题我们用锁
2.1 懒汉模式实现单例模式
①、错误代码1
//懒汉模式:第一次获取对象时再创建对象
class Singleton
{
public:static Singleton* GetInstance(){_mtx.lock();if (_pinst nullptr){//因为是静态成员变量除了第一次为nullptr//再进来不是nullptr了直接返回_pinst即可_pinst new Singleton;}_mtx.unlock();return _pinst;}Singleton(const Singleton s) delete;private:Singleton(){}static Singleton* _pinst;//静态成员的声明static mutex _mtx;
};Singleton* Singleton::_pinst nullptr;//静态成员的定义
mutex Singleton::_mtx; 上面代码意义是创建对象保证只有一个线程在访问解决了不会同时创建对象的问题但是如果new失败了要抛异常怎么办此时正在访问的线程都没有解锁其他线程也无法访问了故要用unique_lock也会帮你锁且不管你是否主动unlock解锁都会在出了作用域后解锁 ②、用unique_lock来改进 ③、只需第一次加锁
只要_pinst指向已经new出来的实例对象就无须加锁了 ④、析构单例模式的对象
一般单例模式下的new出来的这个全局唯一对象是不需要释放的因为这种单例模式下的对象整个程序只有一个它是一直在用的没必要释放。 如果你就想要释放的话两种方式
①、静态函数 ②、静态变量的生命周期 #includevector
#includethread
#includemutexnamespace lazy_man
{//懒汉模式:第一次获取对象时再创建对象class Singleton{public:static Singleton* GetInstance(){//_mtx.lock();unique_lock会锁锁完之后不管你是否解锁出了作用域他都会自动解锁而你现在就这一个地方需要锁故再加个{}作用域//{// unique_lockmutex lock(_mtx);// if (_pinst nullptr)// {//因为是静态成员变量除了第一次为nullptr// //再进来不是nullptr了直接返回_pinst即可// _pinst new Singleton;// }//}//双检查if (_pinst nullptr){//加锁只是为了保护第一次{unique_lockmutex lock(_mtx);if (_pinst nullptr){//因为是静态成员变量除了第一次为nullptr//再进来不是nullptr了直接返回_pinst即可_pinst new Singleton;//只要_pinst指向已经new出来的实例对象就无须加锁了}}}//_mtx.unlock();return _pinst;}//如果你就想释放这个对象的话自己写个静态函数即可手动调static void DelInstance(){unique_lockmutex lock(_mtx);delete _pinst;_pinst nullptr;}Singleton(const Singleton s) delete;private:Singleton(){}static Singleton* _pinst;//静态成员的声明static mutex _mtx;};Singleton* Singleton::_pinst nullptr;//静态成员的定义mutex Singleton::_mtx;//1、如果要手动释放单例对象可以调用DelInstance//2、如果需要程序结束时正常释放单例对象可以加入下面的设计class GC{public:~GC(){Singleton::DelInstance();}};static GC gc;//main函数结束就会调用它的析构函数进而释放_pinstvoid x(){Singleton s1; //失败保证获取的对象每次都是同一个//cout Singleton::GetInstance() endl;//cout Singleton::GetInstance() endl;//cout Singleton::GetInstance() endl;Singleton copy(*Singleton::GetInstance());//无法调用拷贝构造//代码中存在线程问题若多个线程同时获取一个对象呢vectorstd::thread vthreads;int n 4;for (size_t i 0; i n; i){vthreads.push_back(std::thread([](){//cout std::this_thread::get_id() :;cout Singleton::GetInstance() endl;}));//线程对象里面用了一个lambda表达式}for (auto t : vthreads){t.join();}}
}int main()
{lazy_man::x();return 0;
}
运行结果 2.2 饿汉模式实现单例模式 饿汉模式有个静态成员变量静态变量在程序运行前创建在程序的整个运行期间始终存在他始终保持原先的值除非给他赋予一个不同的值或程序结束。正因为程序前创建那此时只有主线程不存在线程安全问题。 namespace hungry_man
{//饿汉模式 --main函数之前就创建对象class Singleton{public:static Singleton* GetInstance(){return _inst;}Singleton(const Singleton s) delete;private: Singleton(){}static Singleton _inst;};//static对象是在main函数之前创建的这时只有主线程故不存在线程安全问题Singleton Singleton::_inst; void x(){Singleton s1; //失败保证获取的对象每次都是同一个//cout Singleton::GetInstance() endl;//cout Singleton::GetInstance() endl;//cout Singleton::GetInstance() endl;Singleton copy(*Singleton::GetInstance());//无法调用拷贝构造//代码中存在线程问题若多个线程同时获取一个对象呢vectorstd::thread vthreads;int n 4;for (size_t i 0; i n; i){vthreads.push_back(std::thread([](){//cout std::this_thread::get_id() :;cout Singleton::GetInstance() endl;}));//线程对象里面用了一个lambda表达式}for (auto t : vthreads){t.join();}}
}int main()
{hungry_man::x();return 0;
} 2.3懒汉和饿汉模式的区别