繁体   English   中英

在C ++中修改std :: unordered_map元素的值

[英]Modify the value of a std::unordered_map element in C++

我有以下问题。 我有一个std::unordered_map ,其中包含一个对象作为值。 现在,我想修改先前插入的对象。

class Point
{
public:
    Point(float _x, float _y) : x(_x), y(_y) {}

    float x;
    float y;
};
std::unordered_map<int, Point> points;
// ... add some values to it ...
points[1].x = 20.f; // error?

我收到一个奇怪的长期编译错误,提示无法默认构造点。 我对它的理解方式operator []返回对映射类型(也就是值)的引用,那么为什么不能修改它呢?

如果密钥不在地图中,则需要 operator []创建密钥。 表达方式

points[1]

需要能够在查找失败的情况下默认插入Point (无论是否发生查找失败-这是编译时的要求,而不是运行时检查)。 Point无法满足该要求,因为Point无法默认构造。 因此,编译错误。 如果要使用unordered_map::operator[] ,则需要添加一个默认构造函数。

如果默认构造的Point对您的用法没有意义-那么您根本就无法使用operator[] ,而必须在整个过程中使用find at()如果可以,请使用at()除非有例外):

auto it = points.find(1);
if (it != points.end()) {
   it->second.x = 20.f;
}

points.at(1).x = 20.f; // can throw

如果给定键不存在任何元素, operator[]将就地构造一个映射类型的对象。 在具有默认分配器的映射中, operator[]要求映射类型是默认可构造的 更一般而言,映射类型必须是可置换的

简单的解决方案是向您的类添加默认构造函数。

Point() : Point(0.f, 0.f) {}

如果无法做到这一点,则必须使用其他功能来访问地图元素。

要访问现有的映射对象,可以使用at ,如果给定键不存在任何元素,则将抛出std::out_of_range异常。

points.at(1).x = 20.f;

另外,您可以使用find ,它使用给定的键将迭代器返回到元素,或者如果不存在映射元素,则返回迭代器到映射中最后一个元素之后的元素(请参见end )。

auto it = points.find(1);
if (it != points.end())
{
    it->second = 20.f;
}

如果数据不可默认构造,则无法在mapunordered_map上使用operator[] 这是因为如果找不到该对象,它将通过default-construction创建它。

简单的解决方案是使您的类型默认可构造。

如果不:

template<class M, class K, class F>
bool access_element( M& m, K const& k, F&& f ) {
  auto it = m.find(k);
  if (it == m.end())
    return false;
  std::forward<F>(f)(it->second);
  return true;
}

然后:

std::unordered_map<int, Point> points;
points.emplace(1, Point(10.f, 10.f));
access_element(points, 1, [](Point& elem){
  elem.x = 20.f;
});

将做什么points[1].x = 20.f; 这样做无需冒任何例外代码的风险,也不必使Point默认可构造。

这种模式-我们在其中传递了一个函数来将元素变异/访问到容器中-从Haskell monad设计中窃取了一个页面。 我会让它返回optional<X>而不是bool ,其中X是传入函数的返回类型,但这有点过头了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM