1

考虑下面的程序,这是一个试图重现一些遗留代码问题的最小示例:

#include <iostream>
#include <ext/hash_map>

// Define a hash for std::string class so we can use it as keys
// in hash_map below.
namespace __gnu_cxx {
    template <>
        struct hash<std::string> {
            size_t operator() (const std::string& x) const {
                return hash<const char*>()(x.c_str());
            }
        };
}

// Data class contains a string
class Data {
    public:
        std::string s;
        Data() { s = "foobar"; }
        Data(std::string s_) : s(s_) {}
};

// Map keyed by string.  Values are Data instances
typedef __gnu_cxx::hash_map<std::string, Data> DataMap;

int main()
{
    DataMap m;
    std::string key = "test";

    // I am storing a "Data" instance d, for "key".  d.s is the same as key.
    Data d = Data(key);
    m[key] = d;

    DataMap::iterator it = m.find(key);
    if (it == m.end()) {
        std::cerr << "not there " << std::endl;
        return 1;
    }
    Data *dp = &it->second;
    // Question about the following line.  Is the behavior well-defined?
    m.erase(dp->s);

    return 0;
}

我将我的类Data实例存储在hash_map. 我使用 搜索特定数据成员key,然后使用 删除该值m.erase(dp->s)m.erase(dp->s)将删除 指向的对象dp。我是否可以dp->s在调用中使用erase(),或者我必须先制作一个副本,然后erase()

std::string key_to_delete = dp->s;
m.erase(key_to_delete);
4

1 回答 1

1

查看实现,似乎即使在it删除节点(由 指向的对)之后,传递给erase函数的键仍然被引用。如果dp被删除,那么对的引用将dp->s变为无效。然而, 的实现hash_map仍在尝试取消引用它。失败。

您需要传递一些保证对调用保持有效的内容erase

你可以

m.erase(key);

或者您可以使用返回的迭代器find进行擦除:

m.erase(it);
于 2013-09-10T06:18:02.610 回答