【问题标题】:Reference as key in std::map引用作为 std::map 中的键
【发布时间】:2010-07-13 09:43:59
【问题描述】:

假设一些数据结构:

typedef struct {
    std::string s;
    int i;
} data;

如果我在std::map<std::string&, data> 类型的映射中添加data 的实例时使用字段data.s 作为键,是否会复制字符串?删除地图元素是否安全,因为引用将变为无效?

这些问题的答案是否也适用于unordered_map

编辑:

这是我目前的解决方案...但是将迭代器添加到地图是丑陋的:

typedef struct {
    const std::string* s;
    int i;
} data;

std::map<std::string, data> map;
typedef std::map<std::string, data>::iterator iterator;

// add an element to the map
iterator add_element(const std::string& s) {
    std::pair<iterator, bool> p = states.insert(std::make_pair(s, data()));
    iterator i = p.first;
    if(p.second) {
        data& d = (*i).second;
        d.s = &(*i).first;
    }
    return i;
}

【问题讨论】:

    标签: c++ map reference


    【解决方案1】:

    C++11

    由于 C++11 reference wrapper 是标准的一部分。

    #include <functional> 
    
    std::map<std::reference_wrapper<std::string>, data>
    

    使用 Boost

    您可能想看看boost.ref。它提供了一个包装器,使引用能够在 STL 容器中使用,如下所示:

    std::map<boost::reference_wrapper<std::string>, data>
    

    【讨论】:

    • 但是我仍然可以更改引用的对象,这意味着我可以动态更改键,这是不允许的,因为它违反了映射底层数据结构 RB 树或 AVL 中元素顺序的稳定性树?
    【解决方案2】:

    您不能将引用存储在标准库容器中 - 您的地图应如下所示:

    map <string,data> mymap;
    

    地图将为您管理密钥字符串和结构实例,它们将是副本。 mapunordered_map 在这方面的工作方式相同,所有其他标准库容器也是如此。

    请注意,在 C++ 中,您不需要 typedef 来声明结构:

    struct data {
        std::string s;
        int i;
    };
    

    【讨论】:

    • 感谢您的回答。如果我想避免拥有两个字符串副本,我是否应该改用 struct data 中的引用?
    • 另外,当你说我不能存储引用时,你的意思是 STL 强制复制吗?
    • @Helltone 引用很难正确地用作结构或类的成员——这并不是它们的真正用途。相反,您应该使用指针,或者完全从结构中省略字符串。
    • @Helltone 是的,所有标准库容器都存储副本。
    【解决方案3】:

    您不能使用参考。地图可以复制内容。我猜这取决于实现。

    但使用 microsoft STL 进行测试。

    struct data
    {
                data(data const& rhs)
                {
                   a new object will be created here
                }
                std::string s;
                int i; 
    };
    

    将一些对象添加到地图中,您将遇到复制构造函数。 这应该会使您的参考无效。

    【讨论】:

      【解决方案4】:

      如果您选择指针而不是对象,我认为不会有很大的性能提升。仅当您管理具有大量需要保存在容器内的现有字符串对象的数据时才执行此操作。此外,在销毁容器之前必须手动管理对象的销毁。

      【讨论】:

        猜你喜欢
        • 2011-06-23
        • 2014-08-06
        • 2015-03-04
        • 1970-01-01
        • 2011-05-08
        • 1970-01-01
        • 2012-04-30
        • 1970-01-01
        相关资源
        最近更新 更多