以数组方式读取map元素的问题

zwyl2001 2008-02-14 04:49:17
以数组方式读取map元素的时候,如果map的key中不存在指定的数据。会不会出现内存泄露之类的问题。和大家讨论一下。比如:
#include <iostream>
#include <map>
#include <string>
using namespace std;

struct MapData {
string data;
int index;
};

int main() {
map<string, MapData> dataMap;
char temp[5] = {0};
for(int i = 0; i < 10; i++) {
itoa(i, temp, 10);
MapData data;
data.data = "data" + string(temp);
data.index = i;
dataMap["data" + string(temp)] = data;
}

for(int i = 0; i < 20; i++) {
itoa(i, temp, 10);
//这段代码,已经调试通过。但是当i大于9时,下面这种写法会不会存在风险。希望大家踊跃讨论。
MapData data = dataMap["data" + string(temp)];
if (data.data == "") {
cout << "data not found: data" + string(temp) << endl;
} else {
cout << "data:" << data.data << "Index: " << data.index << endl;
}
}
}

C++的map以[]方式存取数据是以什么方式进行的。读取时,如果key不存在,有时一什么机制返回什么样的数据的?
...全文
809 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
nsdcomputer 2008-02-14
  • 打赏
  • 举报
回复
总结一下吧, 但调用
dataMap["data" + string(temp)];
时, 实际的动作为: 先在map中找, 如果没有找到了, 则返回相应的值, 如果没有找到, map对象会自动为你建立一个pair对象插入map中, 其中"键"为[]中的, "值" 如果是基本变量, 则赋值为0, 否则调用相应的构造函数
nsdcomputer 2008-02-14
  • 打赏
  • 举报
回复
最后, 我们来看看lower_bound这个函数吧(证明上面所说的):

iterator lower_bound(const key_type& _Keyval) //这个是为_Where赋值的函数!
{ // find leftmost node not less than _Keyval in mutable tree
return (_TREE_ITERATOR(_Lbound(_Keyval)));
}

我们先看函数:

_Nodeptr _Lbound(const key_type& _Keyval) const
{ // find leftmost node not less than _Keyval ----说得很清楚
_Nodeptr _Pnode = _Root();
_Nodeptr _Wherenode = _Myhead; // end() if search fails ----很清楚
...
return (_Wherenode); // return best remembered candidate
}


再看宏 _TREE_ITERATOR

#define _TREE_ITERATOR(ppnode) iterator(ppnode, this)

iterator(_Nodeptr _Pnode, const _Myt *_Plist=NULL)
: const_iterator(_Pnode, _Plist) //注意 class iterator:public const_iterator { // construct with node pointer _Pnode
}

我们发现, 这个宏其实调用了iterator的构造函数, 即代表了iterator的一个对象;
nsdcomputer 2008-02-14
  • 打赏
  • 举报
回复
读取时,如果key不存在,有时一什么机制返回什么样的数据的?

2.那么 mapped_type() 到底代表了什么呢? 我跟踪了一下代码(反汇编):

_Where = this->insert(_Where, value_type(_Keyval, mapped_type()));


0041256A lea ecx,[ebp-14Ch]
00412570 call MapData::MapData (411168h)
...
004125DF mov ecx,dword ptr [ebp-14h]
004125E2 call std::_Tree<...>::insert (41132Fh)
...
0041262E lea ecx,[ebp-14Ch]
00412634 call MapData::~MapData (411172h)


很显然, mapped_type() 构造了一个临时的 MapData 对象;
MapData又是什么呢? 继续跟踪之:

MapData::MapData:
...
004121D5 mov ecx,dword ptr [this]
004121D8 call dword ptr [__imp_std::basic_string<...> (4243DCh)]
...


发现MapData是一个basic_string类的构造函数(注意: basic_string是string类的基类);

也就是说, 在此例中, 如果 但for循环到i大于9 时, 在执行"dataMap["data" + string(temp)]" 这句话时, 我们会调用string 的构造函数; 也就是map 构造函数的第二个参数的构造函数; string 默认构造出来的值为 ""; 所以就是你程序中用(data.data== "") 来判断是能起到想要的结果; 如果第二个参数是你自己写的类, 那就要注意了; 注意当第二个参数是int, long, float, double, char 时, 都被赋值为0;
baihacker 2008-02-14
  • 打赏
  • 举报
回复
6.6.1 Abilities of Maps and Multimaps
Like all standardized associative container classes, maps and multimaps are usually implemented as balanced binary trees (Figure 6.9). The standard does not specify this but it follows from the complexity of the map and multimap operations. In fact, sets, multisets, maps, and multimaps typically use the same internal data type. So, you could consider sets and multisets as special maps and multimaps, respectively, for which the value and the key of the elements are the same objects. Thus, maps and multimaps have all the abilities and operations of sets and multisets. Some minor differences exist, however. First, their elements are key/value pairs. In addition, maps can be used as associative arrays.
nsdcomputer 2008-02-14
  • 打赏
  • 举报
回复
C++的map以[]方式存取数据是以什么方式进行的。

跟踪一下代码吧:
1. 跟踪 [] 的重载:
mapped_type& operator[](const key_type& _Keyval)
{ // find element matching _Keyval or insert with default mapped
iterator _Where = this->lower_bound(_Keyval);
if (_Where == this->end()|| this->comp(_Keyval, this->_Key(_Where._Mynode())))
_Where = this->insert(_Where, value_type(_Keyval, mapped_type()))
return ((*_Where).second);
}

函数operator[] 的作用是:
调用函数lower_bound从左往右查找, 找到第一个符合的对象(如果找不到,则返回end() ), 把这个对象转化成一个iterator对象, 并为变量_Where赋值;
if 中的语句是用来测试_Where的返回情况的, 当用 _Keyval 在 map 中找到了相应的对象, 语句返回假, 否则就为真;
如果在 map 中找到了相应的对象, 则返回(*_Where).second
如果在 map 中没有找到相应的值(此时_Where为end()), 则 operator[] 函数的动作是在 map 的 _Where处( 即end()处) 插入一个pair对象value_type(_Keyval, mapped_type()); 此时的返回值 (*_Where).second 为 mapped_type();
JYeung 2008-02-14
  • 打赏
  • 举报
回复
map 用 rb树的,没记错的话
唐巧 2008-02-14
  • 打赏
  • 举报
回复
另外,map内部并不是用数组来实现数据的存储,而是用(hash表或平衡二叉树)来实现的,只不用是重载了[]操作符,让你看起来象数组取下标,实际上和数组毫无任何关系。
唐巧 2008-02-14
  • 打赏
  • 举报
回复
C++的map以[]方式存取数据是以什么方式进行的。读取时,如果key不存在,有时一什么机制返回什么样的数据的?
--------------------------------------------------------------------------------------
侯捷翻译的<STL标准模版库>把这个问题说得很清楚了。
上面3楼也贴出了这本<STL标准模版库>的英文版相应内容。
大概就是说,如果map的key对应的值在原map中不存在的话,map会首先插入这一元素,然后调用value类型的默认构造函数来对value做初使化操作。
所以你不能以这种方式来进行查找,因为如果这样查找的话,每找不到,就会插入这个元素。
正确的方法是用map.find(key)方式来查找,如果未找到,则返回map.end();
gccli 2008-02-14
  • 打赏
  • 举报
回复
不会,它会插入一个实例,如下代码:
它会将键/值对 string( "key" ), 0
插入到words中
int main(){
map<string,short> words;
short value = words["key"];
map<string,short>::iterator it = words.begin();
cout<<(*it).first<<endl;
cout<<value<<endl;
return 0;
}


测试结果:
key
0
cunsh 2008-02-14
  • 打赏
  • 举报
回复
map的[]和数组没有关系.
cunsh 2008-02-14
  • 打赏
  • 举报
回复
<<STL源码剖析>>
baihacker 2008-02-14
  • 打赏
  • 举报
回复
Table 6.32. Direct Element Access of Maps with Operator [ ] Operation Effect
m[key] Returns a reference to the value of the element with key key Inserts an element with key if it does not yet exist


The type of the index is not the only difference from ordinary arrays. In addition, you can't have a wrong index. If you use a key as the index, for which no element yet exists, a new element gets inserted into the map automatically. The value of the new element is initialized by the default constructor of its type. Thus, to use this feature you can't use a value type that has no default constructor. Note that the fundamental data types provide a default constructor that initializes their values to zero (see page 14).
baihacker 2008-02-14
  • 打赏
  • 举报
回复
标准库文档:
6.6.3 Using Maps as Associative Arrays
Associative containers don't typically provide abilities for direct element access. Instead, you must use iterators. For maps, however, there is an exception to this rule. Nonconstant maps provide a subscript operator for direct element access (Table 6.32). However, the index of the subscript operator is not the integral position of the element. Instead, it is the key that is used to identify the element. This means that the index may have any type rather than only an integral type. Such an interface is the interface of a so-called associative array.

Table 6.32. Direct Element Access of Maps with Operator [ ] Operation Effect
m[key] Returns a reference to the value of the element with key key Inserts an element with key if it does not yet exist


The type of the index is not the only difference from ordinary arrays. In addition, you can't have a wrong index. If you use a key as the index, for which no element yet exists, a new element gets inserted into the map automatically. The value of the new element is initialized by the default constructor of its type. Thus, to use this feature you can't use a value type that has no default constructor. Note that the fundamental data types provide a default constructor that initializes their values to zero (see page 14).

This behavior of an associative array has both advantages and disadvantages:

The advantage is that you can insert new elements into a map with a more convenient interface.

For example:

std::map<std::string,float> coll; // empty collection
/*insert "otto"/7.7 as key/value pair
*-first it inserts "otto"/float()
*-then it assigns 7.7
*/
coll["otto"] = 7.7;


The statement

coll["otto"] = 7.7;


is processed here as follows:

Process coll["otto"] expression:

If an element with key "otto" exists, the expression returns the value of the element by reference.

If, as in this example, no element with key "otto" exists, the expression inserts a new element automatically with "otto" as key and the value of the default constructor of the value type as the element value. It then returns a reference to that new value of the new element.

Assign value 7.7:

The second part of the statement assigns 7.7 to the value of the new or existing element.

The map then contains an element with key "otto" and value 7.7.

The disadvantage is that you might insert new elements by accident or mistake. For example, the following statement does something you probably hadn't intended or expected:

std::cout << coll ["ottto"];

It inserts a new element with key "ottto" and prints its value, which is 0 by default. However, it should have generated an error message telling you that you wrote "otto" incorrectly.

Note, too, that this way of inserting elements is slower than the usual way for maps, which is described on page 202. This is because the new value is first initialized by the default value of its type, which is then overwritten by the correct value.

neilxp 2008-02-14
  • 打赏
  • 举报
回复
不会存在风险,查找不到而已,看看stl源代码就知道了
zwyl2001 2008-02-14
  • 打赏
  • 举报
回复
这是上面例子的运行结果:

data:data0 Index: 0
data:data1 Index: 1
data:data2 Index: 2
data:data3 Index: 3
data:data4 Index: 4
data:data5 Index: 5
data:data6 Index: 6
data:data7 Index: 7
data:data8 Index: 8
data:data9 Index: 9
data not found: data10
data not found: data11
data not found: data12
data not found: data13
data not found: data14
data not found: data15
data not found: data16
data not found: data17
data not found: data18
data not found: data19

64,654

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧