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_map
或 map
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> &
来避免前一个问题。
我有一个抽象 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_map
或 map
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> &
来避免前一个问题。