默认值的map<int,int>

104
std::map<int,int> mapy;
++mapy[5];

可以假设mapy[5]将始终为1吗?我的意思是,在我的代码中即使没有明确声明,mapy [5]是否总会在“++”之前获得默认值0?


3
可能是std::map中内置类型的默认值的重复问题。 - bobobobo
6
这个问题比std::map默认值的内置类型的问题早,所以重复的问题应该是std::map默认值的内置类型 - mpromonet
5个回答

149

只要您使用[]操作符访问地图,如果键不存在,它将被添加。 int会触发“值初始化”,因此它将获得值0。


就我所知,未初始化的基本类型 int 的初始值是_未定义的_ - 也就是说它可能是0,也可能是-99765521。您是否曾经在类变量中使用未初始化的 int 并出现了这些古怪的值? 话虽如此,我测试了一下,似乎可以工作。 #include <stdio.h> <map> using namespace std; int main() { map<int,int> m ; for( int i = 0 ; i < 100 ; i++ ) m[i]++ ; for( const pair<int,int>& p : m ) printf( "m[%d] => %d\n", p.first, p.second ) ; } - bobobobo
32
它的工作方式与您想象的不同。int x;使x获得未定义的值。int x = int();再次,x变成0。class foo { int x; foo() : x() {} }; foo f;这里,f.x将是零。 - rep_movsd
1
在C++中,堆和栈内存是未初始化的 - 对象通过其默认构造函数进行初始化 - 该语言对原始类型有默认构造函数,当您以正确的方式调用它时,它们会将其初始化为0。 - rep_movsd
“默认初始化器”这个术语在这里是可怕且错误的。正确的术语是“值初始化”,这就是为什么映射默认值为0的原因。原始类型根本没有默认构造函数/初始化器,可以将它们初始化为零。这很有用,但事实并非如此。C++的初始化非常复杂! - Johannes Overmann
1
@JohannesOvermann - 已更正 - rep_movsd
显示剩余2条评论

67

可以肯定地认为是安全的。

该映射的operator[]指定如下:([map.access])

作用:如果在映射中没有与x等效的键,则将value_type(std::move(x), T())插入映射中。
返回:指向*this中对应于xmapped_type的引用。

T()对除了void([expr.type.conv]/2)的所有T使用值初始化,对于原始类型,值初始化会导致零初始化([dcl.init]/7)

因此,该表达式计算出一个具有零值的对象的引用([dcl.init]/5)

然后operator++调用将该对象增加到一,并计算为一。

(所有引用均为C++11。)


3
不知道为什么你的回答被踩了,因为你是正确的。这正是规格说明书所说的(我自己刚刚检查了一下)。 - Hans de Ruiter

10

Rep_Movsd的答案过于简化,很可能会导致许多极其危险的误解。在C++中,原始数据类型没有初始化器。Louis Brandy曾经有一个精彩的演讲,在其中讨论了Facebook中常见的C++错误之一:对std::map<>[]如何工作的误解,这是一个非常好的资源,尽管他并没有详细介绍std::map<>[]的实际工作方式。

通常情况下,int类型变量并未初始化,与所有基本类型一样是未定义的。虽然如此,在与std::map<>[]一起使用时,int具有默认值零,该值是通过所谓的值初始化过程设置的。值初始化实际上与结构体一般都是相关的。例如

struct Struct {
Struct() : memberVariable() {}
       int memberVariable;
};

将始终将int初始化为零。如果成员变量是其他原始类型,它们也会具有特定的初始化值。例如,以下类型通过值初始化进行初始化:

bool = false
float = 0.0f
enum = (enum type)0
指针 = null 指针
成员指针 = null 成员指针

在处理未明确初始化的数据时要非常小心。最后,请考虑以下代码

map<string, int> myMap;
cout << myMap["Foo"];

这段代码不仅会将整数值始终初始化为0,还会将0插入到映射中。简单回顾一下,原始数据类型如果没有初始化将是未定义的,在某些情况下,比如结构体或映射值初始化时将使用特定值初始化原始数据。


3
C++中的基本数据类型没有初始化器,这种说法过于简单化,很可能会导致危险的误解。"not initialized"不是完全正确的表述。事实上这被称为"默认初始化",但结果确实是一个未确定的值(C++11 8.5/11)。"are undefined"也不准确,应该是未确定的。"structs"的说法不对,C++中没有结构体,而是用类来表示。"value initialization"是正确的。关键在于使用了不同类型的初始化方式。此外,在您的散文中有一些逗号错误。 - Lightness Races in Orbit
“我从未说过结构体是来自C ++。” 如果您已经知道这一点,那么为什么在C ++问题上谈论结构体呢? 那真是荒谬! - Lightness Races in Orbit
1
不,C++中无法创建结构体。只能使用继承的“struct”关键字创建类。您展示的代码包含一个_class_。C++没有结构体。更多阅读:https://dev59.com/F3VD5IYBdhLWcg3wNIvc#36917400 https://dev59.com/k1wY5IYBdhLWcg3wWWq0#34108140 - Lightness Races in Orbit
谢谢提供参考。问题是:由于结构体声明的类具有默认的公共成员,而类声明的类具有默认的私有成员,那么我在初始答案中发布的代码有什么问题? - Rachel Casey
什么都没有问题,代码很好。问题在于文本描述。 “值初始化是一种实际上适用于结构体的过程”,这是不可能的,因为C++没有结构体。 - Lightness Races in Orbit
显示剩余3条评论

9
是的,缺省值将是该类型的默认值。如果您想要另一个默认值,您可以创建一个类,它的行为类似于int但具有不同的默认构造函数。

3

map<int,int>的默认值将为0;

如果您想将其更改为-1,则可以使用以下方法。

#include <bits/stdc++.h>
using namespace std;
  
struct AnotherVal{
    int value = -1; // can be changed as per requirement 
};
  

int main()
{
    map<int, AnotherVal> tempmap;
    cout << tempmap[1].value << endl;
  
    return 0;
} 

输出:

-1

希望这能帮到您!


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接