关于std::map的用法小结

std::map是标准模板库(STL)中的一个模板类,用于实现映射数据结构,由于map类包含在std名字空间下所以使用std::map.

std::map的两个模板参数是用于定义映射的种类,上面的声明说明关键字的类型是CString,值的类型是PITblSettings。即用一个CString的对象唯一映射一个PITblSettings对象,也就是说给出一个CString对象,通过std::map中的成员函数可以得到和这个CString对象绑定的PITblSettings对象,反之亦可(即通过PITblSettings搜寻相对应的CString对象)。

由于std::map是个模板类,所以整个std::map <CString,PITblSettings>   定义了一个类(这就是模板的好处),因此可以写

std::map <CString,PITblSettings>   g_Map;

这样就定义了一个变量,类型是std::map <CString,PITblSettings> 。由于每次定义都需要输入std::map <CString,PITblSettings> 这么长,所以使用typedef将std::map <CString,PITblSettings>   变成CTableSetingMap,因此就上面那句可以写成
CTableSetingMap   g_Map;

std::map是STL中的容器类,STL中所有的容器类都使用迭代器对容器中元素进行访问(如果你不清楚迭代器的话,大可把它当作指针),所有的容器类都使用
iterator   begin();得到指向容器中开头的元素(可看作一个指针)的迭代器,再通过
iterator   end();得到另一个指向尾端的迭代器(亦可看作指针),如下使用:

CTableSetingMap   g_Map;
//   g_Map的初始化,后面说明
CTableSetingMap::iterator   p   =   g_Map.begin(),   pEnd   =   g_Map.end();
while(   p   !=   pEnd   )     //   注意,pEnd指向的是容器末尾,不是一个有效的元素,所以p   !=  pEnd
{
        (   *p   ).//接g_Map这个容器所装的元素的方法(即成员函数或变量)
        ++p;
}
上面的CTableSetingMap::iterator是一个类型,表示迭代器的类型,将其看作指针代码就很容易理解了,这里不能详诉
g_Map是个映射,即表示一组元素和另一组元素之间的关系,又怎能是容器?STL中用了一个类来表示关系pair,它是一个很简单的模板类,有两个模板参数,可大致简单认为如下:

template <   class   A,   class   B   >   class   pair
{
public:
        A   first;
        B   second;
};
因此一个映射的元素就是一个pair的实例,上面的程序现在完善如下
g_Map.push_back(   pair(   "a ",   pitb1   )   );
g_Map.push_back(   pair(   "b ",   pitb2   )   );
while(   p   !=   pEnd   )
{
        if(   (   *p   ).first   ==   "a "   )
                (   *p   ).second.DoSomething();     //   假设DoSomething是PITblSettings的成员函数
        ++p;
}



基本用法

给出了map的基本用法如插入、查找、删除、遍历等等,同时告诉你如何实现双键map,包括

(1) 只有两个键都匹配才命中目标
(2) 两个键中任意一个匹配就命中目标

可以扩展到多键


(一) 介绍
特点:
1.map将Key的object和T的Object绑定到一起,因此是一种Pair Associative Container, 表示其value type为 pair。
2.它同时也是Unique Associative Container,表示没有两个元素具有相同的Key。
3.它还是一种Sorted Associative Container,因此第三个参数只能是less,greater之类的functor, 相比较而言,
  hash table是 equal_to, not_equal_to之类的functor。(二) 基本用法
通过以下范例,可以看出map的一些基本用法: 插入、查找、删除、遍历等等。

/* 这个是MS的bug,看着心烦,屏蔽掉警告 */
#if defined (_MSC_VER)
#pragma warning(disable: 4786)
#endif
#include 
#include 
#include 
int main(int argc, char *argv[])
{
    /* define a map */
    std::map _map;
    
    /* insert */
    _map.insert( std::map::value_type(0, 32.8) );
    _map.insert( std::map::value_type(1, 33.2) );
    _map.insert( std::map::value_type(2, 35.8) );
    _map.insert( std::map::value_type(3, 36.4) );
    _map.insert( std::map::value_type(4, 37.8) );
    _map.insert( std::map::value_type(5, 35.8) );
    
    /* 这个是常用的一种map赋值方法 */
    _map[7] = 245.3;
    
    /* find by key */
    std::map::iterator itr;
    itr = _map.find(4);
    
    if( itr != _map.end() )
    {
        std::cout  << "Item:"  << itr->first << " found, content: " << itr->second << std::endl;
    }
    
    std::cout  << std::endl;
    
    /* delete item from map */
    if( itr != _map.end() )
    {
        _map.erase(itr);
    }
    
    /* travel through a map */
    std::map::iterator itr1  =  _map.begin();
    for(  ;  itr1  !=  _map.end();  ++itr1 )
    {
        std::cout  << "Item:"  << itr1->first << ", content: " << itr1->second << std::endl;
    }
    
    std::cout  << std::endl;
    
    /* empty a map */
    _map.clear();
    
    return 0;
}

(三) 当Key是结构时该如何定义结构
比如 Key是结构MyStruct类型, 此时map可以定义如下:
std::map > _map;
其中Compare 缺省是std::less,这里可以不写,自定义的结构必须实现Compare指定的比较操作,因此自定义结构
MyStruct必须按照如下写法:
struct MyStruct
{
    int key;
    
    bool operator < ( const MyStruct rhs) const
   {
        return key < rhs.key;
   }
};

当然也可以实现全局operator <
bool operator < ( const MyStruct lhs, const MyStruct rhs) 
{
    return lhs.key < rhs.key;
}另外,当Compare 是std::greater时,需要实现 operator >(四) 如何实现两个Key的map, 只有两个Key都匹配才命中目标
可以定义结构MyStruct如下:
struct MyStruct
{
    int key1;
    double key2
    
    bool operator < ( const MyStruct rhs) const
   {
        /* 两个key必须都匹配才命中 */
        return ( key1 < rhs.key1 || key2 < rhs.key2 );
   }
};


(五) 如何实现两个Key的map, 两个Key中任意一个匹配就命中目标
可以定义结构MyStruct如下:
struct MyStruct
{
    int key1;
    double key2
    
    bool operator < ( const MyStruct rhs) const
   {
        /* 两个key任意一个匹配就命中 */
        return ( ( key1 < rhs.key1 || (key1 > rhs.key1 && key2 < rhs.key2 ) ) && ( key2 < rhs.key2 )  );
   }
};

(六) 如果被存储的T允许重复,可用multimap(七) 如果Key本身就是需要被存储的T, 只要将map换成set就好了



在vc6下使用时会出现下面的bug

 

定义一个std::map<int, std::vector<int>>的类型,在vc6中编译不过。

 

可改写成如下代码:


    typedef std::vector<int>            IntVector;
    typedef std::map<int, IntVector>    IntVectorMap;
    IntVectorMap test_map;

 

或是

 

std::map<int, std::vector<int> > test_map;
在最右面的>前面加个空格

 

凡是形如 xxx<xxx<xxx>>这种模板嵌套的情况,c++当前的标准对此会报错,因为>>解析的问题。当前的解决办法是在两个相邻的>>之间添加一个空格。

C++09已经修复了这个问题,在今年即将公布的新标准中,这样定义是没有任何问题的。不同的编译器有不同的处理。自从C++委员会主席加入vc团队后,vc一直在标准兼容上处于领先地位。特别是c++/cli,允许上述写法,C++自然也继承了这个特性,所以在vs2005下编译有可能通过。当然vc6这种老掉牙的东西是不支持的。

但是不应该以是否编译通过为撰写代码的衡量标准,应该按照标准兼容的方式写代码。因此目前而言,为了兼容C++标准,应该在两个大于号之间加空格,以保证这段代码可以在其它编译器下可以工作。


阅读更多
个人分类: STL
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

关闭
关闭
关闭