C++ unordered_map 默认分配器

C++ unordered_map default allocator

我有一个抽象 class (parent) 并且刚刚创建派生 class (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...
    }
}

好的。现在我使用派生 class 如下所示:

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

问题就出来了。

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

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

假设您有一个 std::unordered_map<std::string, int> 并且您执行以下操作:

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];
    }

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

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

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

如果您覆盖这些通过引用返回的指针中的任何一个,则存在内存泄漏的危险,而且您需要在析构函数中将它们全部释放。您可以通过返回 parent * 而不是 parent *& 或在映射中使用 std::unique_ptr<parent> 并在此处返回 std::unique_ptr<parent> & 来避免前一个问题。