我的单身人士可以被多次叫

时间:2019-04-02 05:02:09

标签: android c++ singleton hal

我已经基于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

问题:

  1. 我的单例设计有什么问题吗?是线程安全的问题吗?

  2. 似乎我的单身人士在一个范围内工作正常,但每个 因此包含我的单身人士的lib将创建自己的单身人士, 单身人士不再是“成为单身人士”。是每个造成的问题 动态链接到新的so和“静态变量”成为“局部静态”? 可能吗?如果是这样,如何解决?

5 个答案:

答案 0 :(得分:28)

  
      
  1. 我的单例设计有什么问题吗?是线程安全的问题吗?
  2.   

不。标准保证函数局部static变量的初始化是线程安全的。

  
      
  1. 似乎我的单身人士在一个范围内运作良好,但每个   所以包括我的单身人士的lib将创建自己的单身人士,   单身人士不再是“成为单身人士”。是每个造成的问题   动态链接到新的so和“ staic veriable”变成“ local static”?   可能吗?如果是这样,如何解决
  2.   

那是正确的结论。

将其创建为动态库,而不是创建包含单例实现的静态库。

答案 1 :(得分:4)

很难,尤其是对于共享库。

每个共享库都具有非共享库的独立副本。无需额外照顾,每个人都会有一个单例的副本。

为了拥有不平凡的单身人士,我要做的是

  1. 创建一个非常低级的库来帮助单例-称为LibSingleton

  2. 创建一个了解单例类型的单例模板。它使用魔术静电将大小,typeid(T).name()键以及类型擦除的构造和销毁代码发送到LibSingleton的请求。 LibSingleton返回引用计数RAII对象。

  3. LibSingleton使用共享的互斥锁来返回与名称/大小匹配的先前构造的对象或对其进行构造。如果构造对象,则存储销毁代码。

  4. 当对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