我已经基于c ++ 11实现了一个单例。 但是,在某些情况下,可以多次调用构造函数。
该类将被编译为静态lib和 由其他so lib(一个以上so lib)使用。 而且该系统是一个多线程系统(在Android HAL级别上运行)
/// .h文件:
class Logger
{
public:
/// Return the singleton instance of Logger
static Logger& GetInstance() {
static Logger s_loggerSingleton;
return s_loggerSingleton;
}
private:
/// Constructor
Logger();
/// Destructor
~Logger();
}
/// .cpp文件
Logger::Logger()
{
ALOGE("OfflineLogger create");
}
Logger::~Logger()
{
}
应该创建一次,例如:
03-21 01:52:20.785 728 4522 E : OfflineLogger create
但是我看到它已经创建了多次
03-21 01:52:20.785 728 4522 E : OfflineLogger create
03-21 01:52:20.863 728 2274 E : OfflineLogger create
03-21 01:52:20.977 728 2273 E : OfflineLogger create
03-21 01:52:26.370 728 4522 E : OfflineLogger create
问题:
我的单例设计有什么问题吗?是线程安全的问题吗?
似乎我的单身人士在一个范围内工作正常,但每个 因此包含我的单身人士的lib将创建自己的单身人士, 单身人士不再是“成为单身人士”。是每个造成的问题 动态链接到新的so和“静态变量”成为“局部静态”? 可能吗?如果是这样,如何解决?
答案 0 :(得分:28)
- 我的单例设计有什么问题吗?是线程安全的问题吗?
不。标准保证函数局部static
变量的初始化是线程安全的。
- 似乎我的单身人士在一个范围内运作良好,但每个 所以包括我的单身人士的lib将创建自己的单身人士, 单身人士不再是“成为单身人士”。是每个造成的问题 动态链接到新的so和“ staic veriable”变成“ local static”? 可能吗?如果是这样,如何解决
那是正确的结论。
将其创建为动态库,而不是创建包含单例实现的静态库。
答案 1 :(得分:4)
很难,尤其是对于共享库。
每个共享库都具有非共享库的独立副本。无需额外照顾,每个人都会有一个单例的副本。
为了拥有不平凡的单身人士,我要做的是
创建一个非常低级的库来帮助单例-称为LibSingleton
创建一个了解单例类型的单例模板。它使用魔术静电将大小,typeid(T).name()
键以及类型擦除的构造和销毁代码发送到LibSingleton的请求。 LibSingleton返回引用计数RAII对象。
LibSingleton使用共享的互斥锁来返回与名称/大小匹配的先前构造的对象或对其进行构造。如果构造对象,则存储销毁代码。
当对LibSingleton数据的最后一个引用计数的句柄消失时,LibSingleton将运行销毁代码并清理其无序映射中的内存。
这允许真正简单的单例几乎在任何地方使用。
template<class T>
class singleton {
public:
static T& Instance() {
static auto smart_ptr = LibSingleton::RequestInstance(
typeid(T).name(),
sizeof(T),
[](void* ptr){ return ::new( ptr ) T{}; },
[](void* ptr){ static_cast<T*>(ptr)->~T(); }
);
if (!smart_ptr)
exit(-1); // or throw something
return *static_cast<T*>(smart_ptr.get());
}
protected:
singleton() = default;
~singleton() = default;
private:
singleton(singleton&&) = delete;
singleton& operator=(singleton&&) = delete;
};
使用方式如下:
struct Logger : LibSingleton::singleton<Logger> {
friend class LibSingleton::singleton<Logger>;
void do_log( char const* sting ) {}
private:
Logger() { /* ... */ }
};
答案 2 :(得分:2)
这里有个主意:与其使用单例,这既是您环境中的难题,又是已知的测试和维护问题,只需设计代码以仅创建一个有问题的对象即可。
答案 3 :(得分:0)
静态变量应移至.cpp文件。
简单的方法是仅在.h中保留getInstance()的声明,然后将实现移至.cpp文件。
答案 4 :(得分:-2)
可能是多次定义了您的头文件(如果多个文件including
是此头文件,则是这种情况。请尝试在头文件周围添加防护措施,以防止在头文件被重新定义时使用)已经定义了一次。
根据您的C ++编译器,实际上您可以像这样在文件的第一行添加#pragma once
#pragma once
class Logger
{
public:
/// Return the singleton instance of Logger
static Logger& GetInstance() {
static Logger s_loggerSingleton;
return s_loggerSingleton;
}
private:
/// Constructor
Logger();
/// Destructor
~Logger();
}
预期的效果是最通用的替代效果,即添加这样的宏定义
#ifndef LOGGER_H
#define LOGGER_H
class Logger
{
public:
/// Return the singleton instance of Logger
static Logger& GetInstance() {
static Logger s_loggerSingleton;
return s_loggerSingleton;
}
private:
/// Constructor
Logger();
/// Destructor
~Logger();
}
#endif LOGGER_H