【问题标题】:std::map, pointer to map key value, is this possible?std::map,指向映射键值的指针,这可能吗?
【发布时间】:2010-10-05 16:27:24
【问题描述】:
std::map<std::string, std::string> myMap;

std::map<std::string, std::string>::iterator i = m_myMap.find(some_key_string);
if(i == m_imagesMap.end())
    return NULL;

string *p = &i->first;

最后一行有效吗? 我想将此指针 p 存储在其他地方,它在整个程序生命周期内都有效吗? 但是如果我在这个映射中添加更多元素(使用其他唯一键)或删除一些其他键会发生什么,它不会重新分配这个字符串(键值对),所以 p 将变得无效吗?

【问题讨论】:

  • 简短回答:可能不,长回答:除非您以前使用typedef const std::string string; 而不是using namespace std;,否则它不会编译,这很令人困惑......

标签: c++ stl pointers map


【解决方案1】:

第 23.1.2#8 节(关联容器要求):

插入成员不会影响迭代器和对容器的引用的有效性,而擦除成员只会使迭代器和对被擦除元素的引用无效。

所以 yes 保证存储指向地图元素的数据成员的指针是有效的,除非您删除 那个 元素。

【讨论】:

  • 实际上,不完全... /iterator/ 是稳定的,但保持迭代器稳定并不意味着保持指针稳定(您可以想象垃圾收集器确保每个迭代器都跟踪数据,但不是指针)。
  • 嗯,看来你是对的。虽然标准明确说明了向量、列表和双端队列 - 当引用和迭代器无效时,我在其中找不到任何关于 map/set 迭代器/引用有效性的信息。
  • 是的,格雷格,我们是对的。 23.1.2/8:“插入成员不应影响迭代器和对容器的引用的有效性,而擦除成员应仅使迭代器和对被擦除元素的引用无效。”当然,你会得到我的 +1。
  • 这里的标准措辞有点奇怪,说的是“对容器的引用”……另外,对于 C++11 和无序容器,意图类似,措辞更简洁: insert 和 emplace 成员不应影响对容器元素的引用的有效性,但可能会使容器的所有迭代器无效。擦除成员应仅使迭代器和对擦除元素的引用无效。
  • 请注意:文本已移至新版标准草案中的新章节 p.744, 23.2.4#9。 N3797, 2013-10-13
【解决方案2】:

首先,地图保证稳定;即迭代器不会因元素插入或删除而失效(当然被删除的元素除外)。

但是,迭代器的稳定性并不能保证指针的稳定性!尽管大多数实现通常会使用指针(至少在某种程度上)来实现迭代器(这意味着假设您的解决方案可以工作是相当安全的),您真正应该存储的是迭代器本身 .

你可以做的是创建一个像这样的小对象:

struct StringPtrInMap
{
  typedef std::map<string,string>::iterator iterator;
  StringPtrInMap(iterator i) : it(i) {}
  const string& operator*() const { return it->first; }
  const string* operator->() const { return &it->first; }
  iterator it;
}

然后存储它而不是字符串指针。

【讨论】:

  • 谢谢,但我需要将指针作为 Windows 消息 LPARAM 传递,我可以将迭代器转换为 LPARAM,然后再返回到迭代器吗?
  • 否,但您可以存储迭代器,然后使用 &i->first,这就是您需要的字符串*。正如 Pierre 所说,这应该是最便携和故障安全的解决方案。
  • 嗯 .. 只是看看另一个高度赞成的答案。由于 std (also) 要求 references 是稳定的,这意味着指针,不仅是迭代器,也需要是稳定的。
【解决方案3】:

如果您不确定哪些操作会使您的迭代器无效,您可以在reference 中轻松查找。例如vector::insert 它说:

这有效地增加了向量大小,当且仅当新向量大小超过当前向量容量时,才会自动重新分配已分配的存储空间。矢量容器中的重新分配使之前获得的所有迭代器、引用和指针无效。

另一方面,map::insert 没有提及任何此类内容。

正如 Pierre 所说,您应该存储迭代器而不是指针。

【讨论】:

  • cplusplus.com 是引用此类内容的不良来源。一般来说,cplusplus.com 的例子很差。我不是因为好玩才这么说,但我知道——我已经看过很多次了。质量差的最好例子是cplusplus.com/reference/iostream/ostream/operator%3C%3C.html
  • 不过,与您的答案无关。只是告诉你我对那个网站的看法。
  • 如果手边没有书,你用什么做参考呢? www.cppreference.com 仍然感觉不完整。
  • 黑客词。我经常在 cplusplus.com 上查看函数名称的快速参考。对于“stl”,我查看了 SGI 网站,我觉得它非常好。他们没有记录 C++ 流和其他不在 SGI stl 中的流,所以我在 cplusplus.com 中查找这些流。
  • 但我不建议你相信它的例子,甚至不向它学习。我见过太多的情况,它过度简化了事情甚至是错误的(就像在我的例子中,他们说 operator> 复制?)。他们一直在说 std:: 中的函数是全球性的)。
【解决方案4】:

你为什么要这样做?

你不能改变 *p 的值,因为它是 const std::string。如果您确实更改了它,那么您可能会通过更改元素的排序顺序来破坏容器的不变量。

除非您有其他未在此处给出的要求,否则您应该只获取字符串的副本。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-07-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多