网站首页 > 技术文章 正文
POCO C++是一个开源的C++类库的集合,它主要提供简单的、快速的网络和可移植应用程序的C++开发,这个类库和C++标准库可以很好的集成并填补C++标准库的功能空缺。POCO库的模块化、高效的设计及实现使得POCO特别适合嵌入式开发。在嵌入式开发领域,由于C++既适合底层(设备I/O、中断处理等)和高层面向对象开发,越来越流行。当然POCO也准备好了面对企业级挑战。
Poco C++库是:
- 一系列C++类库,类似Java类库,.Net框架,Apple的Cocoa;
- 侧重于互联网时代的网络应用程序
- 使用高效的,现代的标准ANSI/ISO C++,并基于STL
- 高可移值性,并可在多个平台下可用
- 开源,并使用Boost Software License发布
- 不管是否商用,都完全免费
今天使用Poco提供的单例模板来完成单例的使用,单例的目的是为实现结构对象中只有一个实例,一般使用C++ 写法有下面几种写法
1. 懒汉式
//MyClass.h
class MyClass
{
public:
static MyClass* getInstance()
{
if (m_instance == nullptr)
{
m_instance = new MyClass();
}
return m_instance;
}
private:
MyClass() {} //私有构造函数
MyClass(const MyClass& my);//禁止拷贝构造函数
MyClass& operator=(const MyClass &my); //禁止赋值操作
static MyClass* m_instance;
}
//MyClass.cpp
MyClass* MyClass::m_instance = nullptr;// 存放在Cpp中,若放在.h中,.h被包含多次时重复定义
上面例子存在的问题是:
线程不安全
不能灵活析构单例
解决方案: 在getInstance()中使用m_instance时加锁
class MyClass
{
private:
std::unique_lock<std::mutex> locker(m_mutex);
public:
static MyClass* getInstance()
{
std::unique_lock<std::mutex> locker(m_mutex);
if (m_instance == nullptr)
{
m_instance = new MyClass();
}
return m_instance;
}
static void destory()
{
std::unique_lock<std::mutex> locker(m_mutex);
if (m_instalce)
{
delete m_instance;
m_instance = nullptr;
}
}
}
以上代码解决了线程安全和单例内存释放的问题,但是如果单例对象被多次访问需要多次加锁,效率较低,可以使用双检查机制
static MyClass* getInstance()
{
if (m_instance == nullptr)
{
std::unique_lock<std::mutex> locker(m_mutex);
if (m_instance == nullptr)
{
m_instance = new MyClass();
}
}
return m_instance;
}
这样处理的原因: m_instance != nullptr时表示一定被new过了; m_instance == null,表示可能被new 过,也可能没有被new过。
2. 饿汉式
饿汉式单例代码如下,线程安全的,但是不能手动灵活释放对象
static MyClass* getInstance()
{
static MyClass c;
return &c;
}
3. std::call_once
std::call_once 是C++11新增功能,能够保证在多线程情况下指定函数只被调用一次;具备互斥量的能力,且比互斥量消耗的资源更少;需要与一个标记结合使用std::once_flag。
class MyClass
{
public:
static MyClass* getInstance()
{
std::call_once(flag, [&]()
{
m_instace = new MyClass;
}
return m_instance;
}
static void destory()
{
if (m_instance)
{
delete m_instance;
m_instance = nullptr;
}
}
private:
static MyClass* m_instance;
static std::once_flag flag;
}
MyClass* MyClass::m_instance = nullptr; //定义在.cpp中
std::once_flag MyClass::flag;
缺点是:不能实现多次创建、销毁单例, 调用 getInstance()、destory(),成功创建和销毁一次单例,再次调用 getInstance()、destory() 失败。
以上方式比较老土,个人还是最喜欢用Poco的SingletonHolder模板来实现,现在我们一起来看Poco的终极大招,结合Visual Stduio 2022 通过CMake来写个完整的单例,还没在Visual Stduio中使用CMake,正好练下手。
假设我想把我的Ck600这个类变成单例,怎么做了,直接上代码
Ck600.h
#ifndef CK600_H
#define CK600_H
#include <Poco/Logger.h>
using Poco::Logger;
class Ck600
{
public:
static Ck600* getInstance();
protected:
static Poco::Logger& LOGGER;
};
#endif
看到没只需要在代码中提供一个获取实例的方法getInstance即可
Ck600.cpp
#include <Poco/SingletonHolder.h>
#include "Ck600.h"
Poco::Logger& Ck600::LOGGER = Poco::Logger::get("Ck600");
static Poco::SingletonHolder<Ck600> holder;
Ck600* Ck600::getInstance()
{
return holder.get();
}
只需要我用包含头文件Poco/SingletonHolder.h,然后使用holder包装下即可
下面我们看下执行结果
test.cpp
#include <iostream>
#include "Ck600.h"
using namespace std;
int main()
{
cout << "Hello CMake." << endl;
Ck600* ck1 = Ck600::getInstance();
Ck600* ck2 = Ck600::getInstance();
cout << "ck1------>" << ck1 << endl;
cout << "ck2------>" << ck2 << endl;
return 0;
}
执行结果为
CMake的构建脚本CMakeLists.txt为
# CMakeList.txt: test 的 CMake 项目,在此处包括源代码并定义
# 项目特定的逻辑。
#
cmake_minimum_required (VERSION 3.8)
project ("test")
if (CMAKE_HOST_SYSTEM_NAME MATCHES "Linux")
message("current platform: Linux ")
elseif (CMAKE_HOST_SYSTEM_NAME MATCHES "Windows")
set(DEPS_POCO_INCLUDE_PATH E:\\poco-1.12.4-all\\poco\\include)
set(DEPS_POCO_LIB_PATH E:\\poco-1.12.4-all\\lib64)
else ()
message("current platform: unkonw platform")
endif ()
# 添加依赖头文件路径
include_directories(${DEPS_POCO_INCLUDE_PATH})
link_directories(${DEPS_POCO_LIB_PATH})
file(GLOB SERVER_CODE_SOURCES
"${PROJECT_SOURCE_DIR}/*.h"
"${PROJECT_SOURCE_DIR}/*.cpp"
)
# 将源代码添加到此项目的可执行文件。
add_executable (test ${SERVER_CODE_SOURCES})
#target_link_libraries("PocoFoundation.lib")
if (CMAKE_VERSION VERSION_GREATER 3.12)
set_property(TARGET test PROPERTY CXX_STANDARD 20)
endif()
set(CMAKE_MSVCIDE_RUN_PATH E:\\poco-1.12.4-all\\bin64)
# TODO: 如有需要,请添加测试并安装目标。
总结,打开SingletonHolder其实就是个C++的模板方法
template <class S>
class SingletonHolder
/// This is a helper template class for managing
/// singleton objects allocated on the heap.
/// The class ensures proper deletion (including
/// calling of the destructor) of singleton objects
/// when the application that created them terminates.
{
public:
SingletonHolder():
_pS(0)
/// Creates the SingletonHolder.
{
}
~SingletonHolder()
/// Destroys the SingletonHolder and the singleton
/// object that it holds.
{
delete _pS;
}
S* get()
/// Returns a pointer to the singleton object
/// hold by the SingletonHolder. The first call
/// to get will create the singleton.
{
FastMutex::ScopedLock lock(_m);
if (!_pS) _pS = new S;
return _pS;
}
void reset()
/// Deletes the singleton object.
{
FastMutex::ScopedLock lock(_m);
delete _pS;
_pS = 0;
}
private:
S* _pS;
FastMutex _m;
};
} // namespace Poco
可以看到就是个懒汉模式,只不过使用了模板方法来实现,并且没有实现DoubleCheck。
- 上一篇: 设计模式——单例模式
- 下一篇: C++设计模式解析之单例模式解析
猜你喜欢
- 2024-09-24 学习C++之良好的编程习惯与编程要点
- 2024-09-24 大一萌新看过来,“这样”学C++,让你不再迷茫
- 2024-09-24 学习单例模式引发的思考
- 2024-09-24 C++中相互依赖的全局变量初始化策略
- 2024-09-24 零基础学习C++
- 2024-09-24 c++的面试总结
- 2024-09-24 避免踩坑,C++常见面试题的分析与解答
- 2024-09-24 20道必须掌握的C++题,纸上谈兵惯用伎俩
- 2024-09-24 C++11魔法静态变量magic static
- 2024-09-24 C++11 中值得关注的几大变化
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)