我正在尝试创建自己的容器,这只是std::unordered_map
的包装器,它使用std::vector
跟踪插入顺序。
这是我的(简化)课程:
template <class tKey, class tValue>
class OrderedMap
{
public:
typedef size_t tSize;
inline bool contains(const tKey& key) const { return map_.count(key) > 0; }
inline tValue& at(const tSize& index) { return vector_[index]; }
inline tValue& operator [](const tKey& key)
{
if(!contains(key)) { throw std::out_of_range("Unknown key"); }
return *map_[key];
}
inline void push_back(const tKey& key, const tValue& value)
{
vector_.push_back(value);
map_[key] = &vector_[size()-1];
}
inline void set(const tKey& key, const tValue& value)
{
if(!contains(key)) push_back(key, value);
else *map_[key] = value;
}
private:
std::vector<tValue> vector_;
std::unordered_map<tKey, tValue*> map_;
};
当我尝试执行此代码示例时:
OrderedMap<std::string, std::vector<std::string> > myContainer;
myContainer.set("1", {"11", "12"});
myContainer.set("2", {"21", "22"});
auto myValues = myContainer["1"];
当我尝试访问数据时发生了错误。在此示例中,当程序尝试将数据复制到myValues
时,它会触发一个异常,告诉我向量太长,但在我的代码中的某个地方,它以读取结束取消引用operator []
中的指向者时出现访问冲突错误。
显然我在某个地方犯了一个错误,但我找不到,所以我的代码出了什么问题? 我错过了关于模板参数和引用它们的一些内容吗?
编辑:我正在使用MSVC 12.0编译Windows。
答案 0 :(得分:3)
将指针/引用/迭代器存储到不断增长的向量中的元素通常是一个非常糟糕的主意。在
inline void push_back(const tKey& key, const tValue& value)
{
vector_.push_back(value);
map_[key] = &vector_[size()-1];
}
将元素添加到矢量中,然后在地图中存储指向该元素的指针。这样做的问题是如果你继续向向量添加项目,向量将需要增长,这意味着分配新的内存。这意味着向量中的元素不再是以前的位置,这意味着地图中的所有指针现在都悬空(指向垃圾)。
简单的解决方法是将元素存储在两个地方。您还可以创建std::shared_ptr
并将shared_ptr
存储在两个容器中。