为什么 C + + 映射类型参数在使用[]时需要一个空的构造函数?

参见 C++ standard list and default-constructible types

Not a major issue, just annoying as I don't want my class to ever be instantiated without the particular arguments.

#include <map>


struct MyClass
{
MyClass(int t);
};


int main() {
std::map<int, MyClass> myMap;
myMap[14] = MyClass(42);
}

这给出了下面的 g + + 错误:

/usr/include/c + +/4.3/bits/stl _ map. h: 419: error: no match function for call to‘ MyClass ()’

如果我添加一个缺省构造函数,这样编译就很好了,我确信这不是由于语法不正确造成的。

44045 次浏览

是的。STL 容器中的值需要维护复制语义。IOW,它们的行为需要类似于原语类型(例如 int) ,这意味着它们应该是默认构造的。

如果没有这个(和其他需求) ,就很难在实现 STL 容器的数据结构上实现各种内部复制/移动/交换/比较操作。

根据 C + + 标准,我发现我的答案并不准确:

由20.1.4.1开始:

缺省构造函数不是 需要。某些集装箱类别 成员函数签名指定 作为违约缺省构造函数 参数。 T ()必须是一个定义良好的 表情。

所以,严格来说,你的值类型只需要是默认构造的,如果你碰巧使用的容器函数在其签名中使用了缺省构造函数。

存储在 STL 容器中的所有值的真正要求(23.1.3)是 CopyConstructibleAssignable

对于特定的容器还有其他特定的要求,例如 Comparable(例如对于映射中的键)。


顺便说一下,在 Comeau上编译以下代码时没有错误:

#include <map>


class MyClass
{
public:
MyClass(int t);
};


int main()
{
std::map<int, MyClass> myMap;
}

So this might be a g++ problem.

Check if:

  • 在类声明之后您忘记了“ ;”。
  • MyType 应该相应地声明。
  • No default constructor there...

我认为 std: : map 声明似乎是正确的。

很可能是因为 std: : double 需要它。对使用值语义保存两个值,因此您需要能够在没有参数的情况下实例化它们。因此,代码在不同的地方使用 std: : double 将映射值返回给调用者,这通常是通过实例化一个空对并在返回本地对之前将值赋给它来完成的。

您可以使用 map < int,smart ptr < MyClass > 来解决这个问题,但是这会增加检查空指针的开销。

这个问题随着操作符[]而来。引用 SGI 文档:

返回对象的引用 与特定的 如果地图还没有 包含这样一个物体,operator[] 插入默认对象 data_type().

如果你没有缺省构造函数,你可以使用插入/查找函数。 下面的例子很有效:

myMap.insert( std::map< int, MyClass >::value_type ( 1, MyClass(1) ) );
myMap.find( 1 )->second;

检查 stl: : map 的存储类型的需求。许多 stl 集合要求存储类型包含一些特定的属性(缺省构造函数、复制建构子等)。

没有参数的构造函数是 stl: : map 所需要的,因为当使用关键字调用操作符[]时,该关键字还没有被 map 保留。在这种情况下,操作符[]插入由新键和使用无参数构造函数构造的值组成的新条目。然后返回这个新值。

假设你有以下信息

class Person
{
public:
Person(int age) :age(age){}
Person() {} // default ctor
int age;
};


map<int, Person> m;


// accessing not-existent key, results in assigning default value to that key
m[10];


// creates default object for key:20 first then assigns age
m[20].age = 32;

如果要为一个不存在的密钥分配 age,应该怎么做?

对于 null类型的语言,如 javascript,映射返回 null,在访问对象或其内部字段之前由用户检查。

C + + 采用了不同的方法,使用缺省构造函数创建了 Person,因此完全避免了 null