【问题标题】:C++ map of string to custom class with generics字符串到具有泛型的自定义类的 C++ 映射
【发布时间】:2021-05-06 13:12:10
【问题描述】:

过去几天我一直在尝试解决我在使用 C++ 时遇到的这个问题。这可能是微不足道的,但我找不到解决方案,在互联网上搜索也没有用,所以我会在这里问。

我有一个 C++ 包装器 Singleton 类、一个超类和一些子类。我需要子类的实例是单例的,所以我使用了here 提出的解决方案,因为它最适合我的需求。我需要一个映射来充当从字符串到正确子类的寄存器。具体来说,代码如下:

// The Singleton class
template <typename T>
class Singleton
{
public:
    static T* Instance()
    {
        if (s_instance == NULL) { s_instance = new T(); }
        return s_instance;
    }
protected:
    static T* s_instance;
}

// Superclass
class MySuperclass
{
public:
    inline LPCSTR GetName() { return m_name; }
    
    virtual ~MySuperclass() { }
protected:
    LPCSTR m_name;
    
    MySuperclass(LPCSTR name) { m_name = name; }
}

// Example subclass
class MySubclass : public MySuperclass
{
    // subclass stuff
}

现在,我尝试了很多东西,让我展示一下我尝试过的所有东西:

// Where the problems begin
class MyRegister
{
public:
    static void Register()
    {
        Singleton<MySubclass> mySubclassSingleton;
        LPCSTR name = Singleton<MySubclass>::Instance()->GetName();
        s_classes.insert(std::make_pair(name, mySubclassSingleton));
    }
private:
    static std::unordered_map<LPCSTR, Singleton<MySuperclass>> s_classes;
}

这是我坚持使用的版本,它在insert 上显示错误:

E0304 no instance of overloaded function "std::map&lt;_Kty, _Ty, _Pr, _Alloc&gt;::insert [with _Kty=LPCSTR, _Ty=Singleton&lt;MySuperclass&gt;, _Pr=std::less&lt;LPCSTR&gt;, _Alloc=std::allocator&lt;std::pair&lt;const LPCSTR, Singleton&lt;MySuperclass&gt;&gt;&gt;]" matches the argument list

我试过用std::pair代替std::make_pair,把地图的定义改成:

template <class T : public MySuperclass>
std::unordered_map s_classes<LPCSTR, Singleton<T>> s_classes;

但无济于事,因为第一个导致相同的错误(也使用 [] 运算符给我带来了 [name] 的问题 no operator matches these operands),第二个导致类型错误。

就目前而言,我需要这些类是单例的,并确保它们是单例的,并且我需要一个将标识类的唯一字符串链接到其单例的寄存器。谁能解释为什么这是不可能的,或者 C++ 中的 Java &lt;? extends MySuperclass&gt; 之类的东西可以在这里工作吗?

【问题讨论】:

    标签: c++ dictionary c++11 generics singleton


    【解决方案1】:
    template <class T : public MySuperclass>
    std::unordered_map s_classes<std::string, Singleton<T>> s_classes;
    

    不是有效的 C++。 但是您可以简单地创建一个std::unordered_map&lt;std::string, MySuperclass*&gt; s_classes。 我们的查找映射不需要知道Singleton 模式,它只需要映射到指向相应子类的指针。我们必须使用std::stringstd::wstring 作为键,否则键之间将使用指针比较,而不是字符串比较。或者,我们可以提供自定义比较运算符。

    Singleton 本身也可以简化。 static 局部变量在第一次使用函数时被初始化,这正是我们想要的行为。

    template <typename T>
    class Singleton
    {
        static T *Instance()
        {
            static T instance{};
            return &instance;
        }
    }
    

    我们之前对new 的使用无论如何都会导致内存泄漏,因为从未调用过delete

    现在,我们也可以相应地更新或MyRegister

    class MyRegister
    {
    public:
        static void Register()
        {
            MySubclass *instance = Singleton<MySubclass>::instance();
            s_classes.emplace(instance->GetName(), instance);
        }
    private:
        static std::unordered_map<std::string, MySuperclass*> s_classes;
    }
    

    【讨论】:

    • 从技术上讲,Meyer 的单例模式与 OP 的方法一样是“内存泄漏”;这两个对象都将一直存在,直到应用程序退出。我不会真的认为这是一个泄漏,因为单例的设计并不是要被删除的。
    • @0x5453 这不是真的。如果您不调用delete,则不会调用析构函数并且取决于它是UB:stackoverflow.com/a/9921320/5740428。但是,可以保证具有static 存储持续时间的对象将从mainexit() 调用return 的析构函数。 stackoverflow.com/a/2204628/5740428
    • UB 如果你依赖析构函数的副作用,在这种情况下是默认的。但总的来说,您是正确的,这是一个重要的区别。
    • 谢谢@JanSchultke!尝试过并且工作得很好。也感谢Singleton模式的讲解和升级!!!
    猜你喜欢
    • 2011-03-05
    • 1970-01-01
    • 2012-09-23
    • 1970-01-01
    • 2021-11-22
    • 1970-01-01
    • 2012-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多