【问题标题】:changing value in a stl map in place更改 stl 映射中的值
【发布时间】:2009-12-29 23:06:51
【问题描述】:

我了解当我们将值插入 STL 映射时,会制作并存储一个副本。 我的代码本质上是在地图上进行查找并获得迭代器。

然后我打算使用迭代器来更改地图中的值。 结果不是我所期望的,即:从程序的另一部分访问时,值不会改变。我怀疑是因为我正在应用的更改是 价值。 相关代码如下。

ObjectMappingType::iterator it = objectMapping_.find(symbol);

if (it == objectMapping_.end()) {
    throw std::invalid_argument("Unknown symbol: " + symbol);
}
get<3>(it->second) = value;

注意:我实际上是在尝试更改 boost::tuple 中的一个值,该值存储为地图的“值”部分。

【问题讨论】:

  • 来自我之前关于元组可变性的问题。双 d = 2.7;一个;元组 t(1, d, a);双 e = 得到(t); // ok from boost.org/doc/libs/1_41_0/libs/tuple/doc/… get() 获取元组的第四个成员。
  • 您如何检查该值是否未更改?您是否尝试在示例的最后一行之后直接assert()
  • 其实我只是打印出来的。在与更改相同的功能中打印出指示值已更改。但在不同的功能中,它似乎并没有改变,这让我相信我改变了一个本地人。
  • 假设 get&lt;&gt;() 像宣传的那样工作,上面的代码应该可以工作 - 我怀疑你有不同的问题。
  • 好吧,既然有人说它可以工作,我建议发布一个可以编译但仍然无法工作的程序。

标签: c++ stl boost map


【解决方案1】:

嗯...这两种方法对我来说似乎都很好。这是我使用的整个示例:

#include <iostream>
#include <map>
#include <string>
#include <boost/tuple/tuple.hpp>

typedef boost::tuple<int, std::string> value_type;
typedef std::map<int, value_type> map_type;

std::ostream&
operator<<(std::ostream& os, value_type const& v) {
    os << " number " << boost::get<0>(v)
       << " string " << boost::get<1>(v);
    return os;
}

int
main() {
    map_type m;

    m[0] = value_type(0, "zero");
    m[1] = value_type(0, "one");
    m[2] = value_type(0, "two");

    std::cout
        << "m[0] " << m[0] << "\n"
        << "m[1] " << m[1] << "\n"
        << "m[2] " << m[2] << "\n"
        << std::endl;

    boost::get<0>(m[1]) = 1;

    map_type::iterator iter = m.find(2);
    boost::get<0>(iter->second) = 2;

    std::cout
        << "m[0] " << m[0] << "\n"
        << "m[1] " << m[1] << "\n"
        << "m[2] " << m[2] << "\n"
        << std::endl;

    return 0;
}

输出完全符合我的预期。

lorien$ g++ -I/opt/include -gdwarf-2 foo.cpp 
lorien$ ./a.out
m[0]  number 0 string zero
m[1]  number 0 string one
m[2]  number 0 string two

m[0]  number 0 string zero
m[1]  number 1 string one
m[2]  number 2 string two
lorien$

【讨论】:

  • 我很震惊你经历了这个麻烦!我必须验证并回复。
  • 呵呵呵呵...boost::tuple最近引起了我的兴趣,看了一整天的文档,我有心情写一些代码;)
【解决方案2】:

map 上的 operator[] 将提供对实际包含的元素的引用,但如果之前不存在地图条目,它会产生令人讨厌的副作用,即创建一个 map 条目。由于您已经在检查 find() 的结果以查看密钥是否存在,因此您可以安全地使用它。

get<3>(objectMapping_[symbol]) = value;

【讨论】:

  • it->second 是对“实际包含的元素”的引用
  • 嗯,也许我还有其他事情要做,这两种方法似乎都不起作用。
  • @Neil:这是我的直觉,但文档很难理解。重新阅读时,我的结论是 (*it) 是对内部映射节点的引用,因此 it->second 确实是对存储值的引用。但初读时并不明显。
  • 如果不提供取消引用的引用,通过迭代器对元素的写访问还有什么其他方式可以工作?
  • @gf:合乎逻辑,我敢肯定我过去曾这样使用过。但我去寻找支持文件,发现它缺乏。我找不到迭代器提供写访问的任何保证。 Operator[] 更容易理解。
【解决方案3】:

如果没有看到更多您的代码,我无法确定这一点,但听起来您可能遇到了线程问题。您的程序是否有机会使用多个线程?也许甚至没有明确地,但也许您调用了一个在单独的线程中执行某些工作的库?这是我开始调试时要做的事情。

  1. 进行检查以在设置后重新查找映射中的值,并检查它是否是正确的新值,如果不是则抛出异常。
  2. 通过访问“程序的其他部分”中的值来重现错误,并查看它是否抛出异常
  3. 使用调试器逐步检查以确保修改确实发生在程序其他部分的访问之前而不是之后。
  4. 如果访问次数过多而无法手动执行此操作,请将跟踪转储到文件中。也就是说,每次访问地图时添加代码以追加到日志文件。每一行的访问时间都应该与系统时钟允许的分辨率一样高、映射的地址(因此您知道您正在修改同一个映射)、符号键、值和新值(如果这是一个修改访问)。通过这种方式,您可以准确地确定地图修改未在程序的其他部分中显示的时间,以及它们是在访问之前还是之后。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-17
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    相关资源
    最近更新 更多