单例的重复实例化

Duplicate instantiation of singleton

本文关键字:实例化 单例      更新时间:2023-10-16

我们正在做一个关于c++和Matlab通过Mex合作的大型项目,目前我们正在努力解决我们的一个单例。

这个类是在预处理过程中通过宏生成的,所以看起来有点奇怪。

class AdditionalOperation { 
private: 
    const std::string* val; 
    typedef std::map<std::string, const std::string*> StringMap; 
    static StringMap& getStringToPointerMap() 
    { 
        static StringMap map; 
        return map; 
    } 
    static boost::mutex& getMutex()
    { 
        static boost::mutex mutex; 
        return mutex; 
    } 
    AdditionalOperation(const std::string* s)
        :val(s) 
    {} 
private: 
    static std::string* none_string() 
    { 
        static std::string s = "none"; 
        static int count = 0; 
        boost::mutex::scoped_lock lock(getMutex()); 
        if(count++ == 0) { 
            getStringToPointerMap().insert(std::make_pair(s,&s)); 
        } 
        return &s; 
    } 
public: 
    static AdditionalOperation none() 
    { 
        return AdditionalOperation(none_string()); 
    } 
private: 
    static std::string* norm_string() 
    {   
        static std::string s = "norm"; 
        static int count = 0; 
        boost::mutex::scoped_lock lock(getMutex()); 
        if(count++ == 0) { 
            getStringToPointerMap().insert(std::make_pair(s,&s)); 
        } 
        return &s; 
    } 
public: 
    static AdditionalOperation norm() 
    { 
        return AdditionalOperation(norm_string()); 
    } 
private: 
    static void prepare() 
    { 
        none(); 
        norm(); 
    } 
public: 
    static AdditionalOperation fromString(std::string s) 
    { 
        static int count = 0; 
        if(count++ == 0) 
            prepare(); 
        boost::mutex::scoped_lock lock(getMutex()); 
        StringMap& map = getStringToPointerMap(); 
        StringMap::iterator location = map.find(s); 
        if(location == map.end()) { 
            throw UnknownEnumValue(s); 
        } 
        return AdditionalOperation(location->second); 
    } 
    std::string toString() const 
    { 
        return *val; 
    }
    bool operator==(const AdditionalOperation& other) const 
    { 
        return val == other.val; 
    } 
    bool operator!=(const AdditionalOperation& other) const 
    { 
        return !(*this == other); 
    } 
};

所有这些代码都是从这一行生成的(通过如上所述的宏):

DECLARE_SENUM(AdditionalOperation, none, norm);

这是一个很好的界面,我们想继续使用。

我们希望使用该类作为枚举的替代品,因为我们需要将它们从字符串转换为字符串。在这个类中,我们有两个"枚举"成员,即norm和none。

现在我们已经添加了一些日志记录,并且已经确定none_string和norm_string函数中的插入操作被调用了两次,尽管我们的计数器应该防止这种情况发生。

我们尝试过的一些事情:

  • 我们正在使用一个动态库,但是使用-rdynamic没有帮助。
  • 当我们打印静态变量的地址时,我们可以清楚地看到它们的不同。这个类位于一个动态库中,这个动态库又与一个mex文件链接。这个mex文件是由另一个mex文件通过dlopen动态加载的。

我们认为可能由于动态库的关系,该类的多个实例被声明并激活。但是我们也使用其他类型的单例,这些单例没有显示出任何问题的迹象。

我希望它足够清楚,可以随时提供额外的信息或澄清!

提前感谢!

很明显,你把问题复杂化了。

std::string const& to_string(MyEnum e) {
    static std::string const First = "First";
    static std::string const Second = "Second";
    switch(e) {
    case MyEnum::First: return First;
    case MyEnum::Second: return Second;
    }
    throw std::runtime_error("Unknown enum value");
}