一、不能被拷贝的类
#include<iostream>
using namespace std;
class heaponly
{
public:
heaponly() {}
heaponly(const heaponly& ho) = delete;
private:
int _x=0;
};
二、只能在堆上创建对象的类
方法1
#include<iostream>
using namespace std;
class heaponly
{
public:
void Destroy()
{
delete this;
}
private:
//析构私有化
~heaponly() {}
private:
int _x=0;
};
int main()
{
heaponly* d = new heaponly;
//显示调用释放对象空间
d->Destroy();
return 0;
}
方法2
#include<iostream>
using namespace std;
class heaponly
{
public:
static heaponly* Create()
{
heaponly* pj=new heaponly;
return pj;
}
private:
heaponly() { cout << "stackonly()" << endl; }
~heaponly(){}
heaponly(const stackonly& ho) = delete;
heaponly& opertor=(const stackonly& ho) = delete;
int _x=0;
};
int main()
{
heaponly* s1 = heaponly::Create();
return 0;
}
三、只能在栈上创建对象的类
将构造私有,创建静态成员函数,其返回值是栈上开辟的对象.但是这样无法阻止静态区开辟空间的对象接收对象的值.
#include<iostream>
using namespace std;
class stackonly
{
public:
static stackonly Create()
{
return stackonly();
}
//右值引用
stackonly(const stackonly&& ho) { _x = ho._x; }
private:
stackonly() { cout << "stackonly()" << endl; }
stackonly(const stackonly& ho) = delete;
int _x=0;
};
int main()
{
stackonly s1 = stackonly::Create();
//静态区创建对象无法彻底组织
static stackonly s2 = stackonly::Create();
cout << typeid(s2).name() << endl;
return 0;
}
四、只能创建一个对象的类(单例模式)
1.饿汉模式
首先将构造私有化,防止随意构造对象,定义静态成员对象指针,没使用的时候就初始化一个对象.使用时通过调用静态成员返回值静态成员对象指针,用这个指针调用类的成员函数使用类.
#include<iostream>
using namespace std;
class Singleton
{
public:
static Singleton* GetInstance()
{
return _ins;
}
void Add(const string& str)
{
_mtx.lock();
_v.push_back(str);
_mtx.unlock();
}
void Print()
{
_mtx.lock();
for (auto& e : _v)
{
cout << e << endl;
}
cout << endl;
_mtx.unlock();
}
private:
// 限制类外面随意创建对象
Singleton()
{}
private:
mutex _mtx;
vector<string> _v;
static Singleton* _ins;
};
//在类外面定义,任然可以使用类的私有成员--构造函数
Singleton* Singleton::_ins = new Singleton;
2.懒汉模式
懒汉模式相比饿汉模式更加可控,对于对象的创建来说,而且如果对象占内存比较大,一开始运行就创建对象会拖慢程序的运行.懒汉模式实现思想是创建一个静态全局对象变量,初始化为空,设置静态全局成员函数,调用这个函数时如果对象为空,就实例化一个对象并返回对象指针,如果不为空直接返回对象指针.这个对象指针可以调用类的成员函数,实现对类的成员变量的操控.
单例模式下的类对象一般为全局对象,一般不需要显示调用释放资源,调用资源释放函数可以直接释放资源,也可以实现一个内部类,实例化一个此类的静态全局对象,这个类的析构调用单例对象的资源释放函数,当内部类的对象析构时,会将单例对象资源释放.
#include<iostream>
#include<thread>
#include<vector>
#include<string>
#include<mutex>
#include<time.h>
using namespace std;
namespace kk
{
class singleton//单例
{
public:
//如果没有实例化调用create就是实例化,如果实例化了在调用
//就是获取对象指针.
static singleton* getInstance()
{
//如果不为空则直接返回,避免冗余的加锁解锁
if (_instance == nullptr)
{
//锁可能被另一个线程申请,而后_instance被初始化.
_mtx.lock();
if (_instance == nullptr)
{
_instance = new singleton;
}
_mtx.unlock();
}
return _instance;
}
void add(const string& str)
{
//全局只有一个_v所以要加锁
_mtx.lock();
_v.push_back(str);
_mtx.unlock();
}
void print()
{
_mtx.lock();
for (auto x : _v)
{
cout << x << endl;
}
_mtx.unlock();
}
//显示调用释放资源
void delInstance()
{
_mtx.lock();
delete _instance;
_instance = nullptr;
_mtx.unlock();
}
//在程序结束的时候调用Gc的析构释放_singleton对象的资源
class Gc
{
public:
~Gc() {_instance->delInstance();}
};
private:
//防止类外创建对象
singleton() {};
vector<string> _v;
static singleton* _instance;//实例
static mutex _mtx;
static Gc _gc;
};
singleton* singleton::_instance = nullptr;
mutex singleton::_mtx;
singleton::Gc singleton::_gc;
void test()
{
size_t n = 10;
srand((time_t)time(0));
thread t1([n]() {
for (size_t i = 0; i < n; i++)
{
singleton::getInstance()->add("thread1:" + to_string(rand()));
}
});
thread t2([n]() {
for (size_t i = 0; i < n; i++)
{
singleton::getInstance()->add("thread2:" + to_string(rand()));
}
});
t1.join();
t2.join();
//这里的print不能再join之前,因为print与线程并行运行时_v可能是空的.
//当join运行结束,证明线程运行结束了,这个时候可以运行print
singleton::getInstance()->print();
}
}
int main()
{
try
{
kk::test();
}
catch (...)
{
cout << "位置异常" << endl;
}
return 0;
}
懒汉模式对象的创建在C++11版本之后还可以利用静态变量只会被初始化一次的特性来创建.这种方法在C++11之前不是线程安全的,多线程调用次函数可能会创建多个对象.
static singleton<T>* GetInstance()
{
static singleton<T> sl;
return &sl;
}