【问题标题】:C++ unordered_map default allocatorC++ unordered_map 默认分配器
【发布时间】:2020-06-15 17:18:05
【问题描述】:

我有一个抽象类(parent)并且刚刚从它创建了派生类(child),如下所示:

class parent {
public:
    virtual string print()=0;
};

template<class T>
class child: public parent{
private:
    unordered_map<string, parent*> children;
public:
    parent *&operator[](string name) {
        return children[name];
    }
    virtual string print(){
        //some jobs...
    }
}

好的。现在我使用如下派生类:

child<string> a;
a["test"]->print();

问题就出来了。

我认为问题在于 unordered_map::[] 运算符创建了 parent 类的实例,而不是我想要的 child 类。

如何告诉 unordered_map 创建新项目作为 child

【问题讨论】:

  • 在你调用a["test"]-&gt;print();之前你应该在那里添加一个对象,a["test"] = new child&lt;string&gt;;或者在operator[]里面添加if (children.find(name) == children.end()) children[name] = new child&lt;T&gt;;

标签: c++ class inheritance unordered-map


【解决方案1】:

unordered_map&lt;std::string, parent *&gt;::operator[] 不会创建 any 类的实例,因为它的值是指针,而不是类实例。因此,如果您使用它来访问以前未插入到映射中的键,它将默认初始化一个指针(将其初始化为 nullptr)并将其存储在映射中。

如果您想要地图中的任何非 nullptr 值,您需要自己将它们存储在那里。您可以在 operator[] 函数中执行此操作:

parent *&operator[](string name) {
    auto &rv = children[name];
    if (!rv) rv = new child<T>;
    return rv;
}

如果你覆盖了这些通过引用返回的指针中的任何一个,这会有内存泄漏的危险,而且你需要在析构函数中释放它们。您可以通过返回 parent * 而不是 parent *&amp;,或在地图中使用 std::unique_ptr&lt;parent&gt; 并在此处返回 std::unique_ptr&lt;parent&gt; &amp; 来避免前一个问题。

【讨论】:

    【解决方案2】:

    假设您有一个std::unordered_map&lt;std::string, int&gt;,并且您执行以下操作:

    std::unordered_map<std::string, int> m;
    std::cout << m["hello"];
    std::cout << m["key1"];
    

    上述程序不会产生任何警告或错误。事实上,它会输出00。两个零。那么,这里发生了什么?

    unordered_mapmap operator[] 插入一个值,以防密钥不存在。这是 C++ 中无意错误的最大来源之一。在上述情况下,"hello""key1" 不存在,因此它们是在原地创建的,value 默认初始化为 0

    如何解决您的问题?

    在使用operator[] 之前,请务必确保您尝试访问的值是否存在。实际上,如果要执行读取,最好使用.at() 成员函数。

    固定代码:

    child<string> a;
    a["test"] = new child<string>;
    a["test"]->print();
    

    您可以通过更改 operator[] 函数来进一步防止这种行为:

        parent *&operator[](string name) {
            if (children.find(name) == children.end()) // does it exist?
                children[name] = new child<T>; // if it doesn't, create a new one.
            return children[name];
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-04
      • 2019-01-11
      • 1970-01-01
      • 2014-12-07
      • 2011-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多