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


98

另请参见 C ++标准列表和默认可构造类型

这不是什么大问题,只是令人讨厌,因为我不希望在没有特定参数的情况下实例化我的班级。

#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:错误:没有匹配的函数可用于调用“ MyClass()”

如果添加默认的构造函数,编译效果很好;我敢肯定这不是由语法错误引起的。


上面的代码在MinGW(g ++ 3.4.5)和MSVC ++ 2008上可以很好地进行编译,前提是给定MyType的typedef,并且在类末尾附加了分号。您必须做其他事情(例如bb提到的调用operator [])-请发布完整代码。
j_random_hacker 2009年

啊,是的,你是对的。会做。
尼克·博尔顿

是的,如果不使用myMap,您将不知道需要为map类编译什么内容。哪个stl库提供程序和版本也可能会有所帮助。
格雷格·多姆詹

Answers:


165

此问题与operator []一起提供。引用SGI文档:

data_type& operator[](const key_type& k)-返回对与特定键关联的对象的引用。如果地图尚未包含这样的对象,则operator[] 插入默认对象 data_type()

如果没有默认构造函数,则可以使用插入/查找功能。以下示例工作正常:

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

11
出色的答案- emplace在C ++ 11中也请注意,它是的简洁替代insert
骄傲

3
为什么std::<map>::value_typeinsert通话中?
thomthom,2015年

1
为什么默认构造函数需要用户定义?
schuess

@schuess我没有理由这么做:= default应该可以正常工作。
underscore_d

在运行时将评估条件“地图尚未包含此类对象”。为什么会出现编译时错误?
盖拉夫·辛格

8

是。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;
}

因此,这可能是g ++问题。


2
您是否认为bb可能涉及到[]运算符?
尼克·博尔顿

12
该代码可能会编译,因为您没有调用myMap []
jfritz42'8

3

检查stl :: map的存储类型要求。许多stl集合要求存储的类型包含一些特定的属性(默认构造函数,复制构造函数等)。

stl :: map需要没有参数的构造方法,因为使用该方法时,是通过键调用operator []的,而该键尚未被映射保留。在这种情况下,operator []插入新条目,该条目由使用无参数构造函数构造的新键和值组成。然后返回此新值。


-2

检查:

  • 您忘记了“;” 在类声明之后。
  • MyType应该已经被声明了。
  • 那里没有默认的构造函数...

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


如果添加默认构造函数,编译效果很好。
尼克·博尔顿

-2

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

您可以使用map <int,smartptr <MyClass>>使用智能指针解决此问题,但这会增加检查空指针的开销。


2
+0。pair <T,U>可以与没有默认构造函数的T和U类型一起使用-这种情况下唯一不能使用的是pair <T,U>自己的默认构造函数。map <K,V>的体面质量实现都不会使用此默认构造函数,因为它会限制K和V的大小。
j_random_hacker 2009年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.