【问题标题】:Copy/move requirements for the key/value types in a std::map?std::map 中键/值类型的复制/移动要求?
【发布时间】:2023-03-20 06:39:01
【问题描述】:

这段代码让我很困惑:

struct foo {
  int i;

  foo(int j) : i(j) {}

  foo(const foo &) = delete;
  foo(foo &&) = delete;
  foo &operator=(const foo&) = delete;
  foo &operator=(foo&&) = delete;
};

bool operator<(const foo &f1, const foo &f2)
{
  return f1.i < f2.i;
}

int main(int argc, char **argv)
{
  std::map<foo,int> f;
  std::map<foo,int> f2 = f; //error (as expected)
  std::map<foo,int> f3 = std::move(f); //no error (why?)
  return 0;
}

因为我在那里没有收到错误,所以在移动地图时似乎没有创建关键对象(甚至没有将另一个关键对象移动到其中)。

为什么不呢?我可以根据 C++11 标准依赖这种行为吗?

更一般地说,std::map键和值类型有什么复制/移动要求以及在什么条件下?

【问题讨论】:

  • 移动地图对键和值的要求没有
  • @MooingDuck,如果分配器类型不传播,那就不是真的
  • 啊,对,分配器可以搞砸一切。

标签: c++ c++11


【解决方案1】:

将一张地图复制分配到另一张地图需要复制每个项目。由于您无法复制项目,因此您无法复制分配地图。

实际地图对象在运行时是否为空并不重要,因为这些纯粹是静态考虑,完全由对象的类型决定。

(这就像问为什么sin(0) 需要一个浮点单元,而结果显然是一个整数。)

另一方面,移动整个地图很好,因为容器是基于节点的,没有实际值发生变化,只有节点发生变化。事实上,基于移动构造或移动分配节点的容器并不要求元素可复制可移动可分配。

(这对于所有以合适的方式管理动态内存的容器都应该是正确的,例如通过std::allocator&lt;value_type&gt;,但对于像std::array 这样的东西当然不是正确的,不管是否会很有趣它将适用于std::dynarray,并且正如@Jonathan Wakely 所指出的,如果分配方案无法批量移动节点。)

【讨论】:

  • 如果allocator_traits&lt;M::allocator_type&gt;::propagate_on_container_move_assignment::value 为假,则将M 类型的映射移动分配需要将元素类型为MoveInsertableM
  • 该死的该死的分配器:-\
  • 我的 ACCU 2012 C++11 Allocators 谈话的后半部分可能有助于理解这些变化......但可能不会。回复:原始评论,是的,我把它调低了;-)
  • 除了 JonathanWakely 的优秀 cmets 之外,请注意,原始代码实际上不应该在 C++11 中工作,而是在 C++1y 中,因为 propagate_on_container_move_assignment 中的 std::allocator 为 false C++11,但在 C++1y 中是正确的。这种变化被广泛认为是 C++11 中的一个愚蠢的缺陷,并且实现者已经积极地做出了这种变化,而不管客户要求的标准一致性标志。
  • @roger.james,你不需要担心它们,除非在非常特殊的情况下,例如。使用共享内存或非常严格的限制
【解决方案2】:

没有错误,因为只移动了map,而不是map 的元素。只分配指向元素的指针

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-14
    • 2019-04-01
    • 2015-06-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-02
    • 1970-01-01
    相关资源
    最近更新 更多