C++的map容器可以建立映射,如果key使用自定义类,需要重载operator<运算符,但是由于find方法使用operator<来完成, 因此常常会遇到意想不到的意外。尽管有人说可以通过std::find_if通过重载operator==运算来保证可靠查找,但是也会遇到意想不到的意外。
以下的代码中,几种方法在find时均会遇到意想不到的意外,无法可靠find相应的key。
//
// Created by Denlee on 21-12-5.
//
#include <map>
#include <iostream>
#include <algorithm>
#include <assert.h>
class Point {
private:
int _x, _y;
public:
Point();
Point(int x, int y);
Point(const Point &pt);
~Point();
Point &operator=(const Point &pt);
bool operator==(const Point &pt) const;
// partial order
bool operator<(const Point &pt) const;
friend std::ostream &operator<<(std::ostream &out, const Point &pt);
};
Point::Point() {
_x=_y=0;
}
Point::Point(int x, int y) {
_x = x; _y = y;
}
Point::Point(const Point &pt) {
_x = pt._x;
_y = pt._y;
}
Point::~Point() {
}
Point& Point::operator=(const Point &pt) {
if(this != &pt) {
this->_y = pt._y;
this->_x = pt._x;
}
return *this;
}
bool Point::operator==(const Point &pt) const {
return this->_x == pt._x && this->_y == pt._y;
}
bool Point::operator<(const Point &pt) const {
return this->_x < pt._x || this->_y < pt._y;
}
std::ostream &operator<<(std::ostream &out, const Point &pt) {
out << "(" << pt._x << "," << pt._y << ")";
return out;
}
int main() {
int i, j;
int x = 10;
int y = 9;
std::map<Point, int> map_point;
int order = 0;
for(i=0; i<x; i++) {
for(j=0; j<y; j++) {
map_point.insert(std::pair<Point, int>(Point(i,j), order++));
}
}
assert(map_point.size() == x * y);
std::cout << "--------------find-----------------\n";
for(i=0; i<x; i++) {
for(j=0; j<y; j++) {
std::map<Point, int>::const_iterator it;
it = map_point.find(Point(i,j));
if(it != map_point.end()) {
std::cout << it->first << ": " << it->second << "\n";
} else {
std::cout << "(" << i << "," << j << ")\n";
}
}
}
std::cout << "-------------count------------------\n";
for(i=0; i<x; i++) {
for(j=0; j<y; j++) {
Point pt(x,y);
if(map_point.count(pt)) {
std::cout << pt << ": " << map_point[pt] << "\n";
} else {
std::cout << "(" << i << "," << j << ")\n";
}
}
}
std::cout << "---------------find_if----------------\n";
for(i=0; i<x; i++) {
for(j=0; j<y; j++) {
Point pt(x,y);
std::map<Point,int>::iterator it = std::find_if(map_point.begin(),map_point.end(),[pt](std::pair<Point,int> obj){return obj.first == pt; });
if(it != map_point.end()) {
std::cout << it->first << ": " << it->second << "\n";
} else {
std::cout << "(" << i << "," << j << ")\n";
}
}
}
std::cout << "-------------enumerate------------------\n";
for(const auto& v : map_point) {
std::cout << v.first << ": " << v.second << "\n";
}
return 0;
}
对于自定义类作为key,最好使用std::string来表征,并通过自定义比较函数来实现可靠查找.
// Point类增加成员函数
std::string to_string() const;
std::string Point::to_string() const {
return std::to_string(_x) + std::to_string(_y);
}
// 自定义比较函数
class point_key_comp {
public:
bool operator()(const Point& pt1, const Point& pt2)const {
return pt1.to_string() < pt2.to_string();
}
};
//.....
//使用Point类型作为map的key
std::map<Point, int, point_key_comp> map_point;
参考资料:
[1] C++ STL: map自定义键值类型. C++ STL: map自定义键值类型_爱吃柚子的好奶罐-CSDN博客_c++ map 自定义类.
[2] C++ 自定义比较函数(map和multimap)详解. C++ 自定义比较函数(map和multimap)详解.
[3] C++中set/unordered_set 自定义比较规则. C++中set/unordered_set 自定义比较规则_nepu_bin的博客-CSDN博客.
[4] C++ STL无序容器自定义哈希函数和比较规则(超级详细). C++ STL无序容器自定义哈希函数和比较规则(超级详细).