【问题标题】:Why does std::map::operator[] assignment require an argumentless constructor?为什么 std::map::operator[] 赋值需要一个无参数的构造函数?
【发布时间】:2021-10-12 08:44:48
【问题描述】:

我有以下最小示例在我的代码中重现错误:

#include <unordered_map>
#include <iostream>

class B 
{
public:
    B(int b) : m_b{ b } {}
    int m_b;
};

int main()
{    
    using std::cout, std::endl;
    std::unordered_map<int, B> ab{};

    ab[1] = B(3);
    //ab.insert(std::pair<int, B>(1, B(3)));

    cout << ab[1].m_b << endl;
}

这会失败并出现一个冗长且笨拙的错误,基本上等于说没有任何参数的B 没有构造函数。错误源于ab[1] = B(3) 为什么需要?为什么使用insert 而不是operator[] 不需要那个构造函数?

为什么我的原始代码中有这行代码:

Vec2 pos{ m_orbits[&p].positionAtTime(m_time + dt) };

还需要一个非参数化的构造函数。我无法在我的最小示例中重现该错误,但m_orbits 是一个无序映射,其中指向Particle 对象的指针作为键,Orbit 对象作为值。 positionAtTimeOrbitconst 成员函数,用于计算粒子在特定时间在轨道上的位置。

【问题讨论】:

  • 如果没有先创建实例(在左侧),就无法分配(调用 operator=)。
  • ab 是空地图时,ab[1] 应该返回什么?
  • ab[1] = B(3) 失败,因为unordered_map::operator[]() 会在地图中插入一个默认构造的元素(如果不存在)(对于提供的键)。为此,它需要默认为B。返回对映射中相应B 的引用(无论是刚刚构建的还是先前存在的)。在ab[1] = B(3) 中,引用的B 然后被分配B(3) 的结果。基于知道右侧是B,以上没有捷径。

标签: c++ algorithm class c++11 stdmap


【解决方案1】:

为什么需要[B 的构造函数,没有任何参数]?

这是因为std::map::operator[] 要求mapped_type(即在您的情况下为B)是默认可构造的。

  1. 如果密钥不存在,则插入value_type(key, T())。这个函数相当于返回insert(std::make_pair(key, T())).first-&gt;second
    • key_type 必须满足CopyConstructible的要求。
    • mapped_type 必须满足 CopyConstructibleDefaultConstructible 的要求。 如果执行插入,则映射值是值初始化的(类类型默认构造,否则为零初始化)并返回对它的引用。

当您提供用户定义的构造函数(即B(int b))时,compiler will not generate a default constructor automaticallyA 不能被默认构造。

如果存在一些用户声明的构造函数,用户仍可以强制编译器自动生成默认构造函数,否则将使用关键字 default 隐式声明。

因此,出现上述错误!


为什么使用insert 而不是operator[] 不需要那个构造函数?

因为std::map::insert 依赖于value_type(即std::pair&lt;const Key, T&gt;)。对于您的ab,这是std::pair&lt;const int, B&gt;。从 cppreference.com 函数重载:

1-3) 插入值。重载 (2) 等价于 emplace(std::forward&lt;P&gt;(value)),并且仅在 std::is_constructible&lt;value_type, P&amp;&amp;&gt;::value == true 时才参与重载解析。

4-6) 在尽可能靠近的位置插入值,就在之前(C++11 起),以提示。重载 (5) 等价于 emplace_hint(hint, std::forward&lt;P&gt;(value)),并且仅在 std::is_constructible&lt;value_type, P&amp;&amp;&gt;::value == true 时才参与重载解析。

只要B是可构造的,std::pair&lt;const int, B&gt;也可以构造,std::map::insert可以工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-05
    • 2014-04-16
    • 1970-01-01
    • 2012-09-15
    • 2010-09-21
    • 1970-01-01
    • 2011-02-25
    相关资源
    最近更新 更多