【问题标题】:Map having a class as key, allows for duplicate keysMap 有一个类作为键,允许重复键
【发布时间】:2015-10-13 14:10:41
【问题描述】:

我有一个简单的地图程序。它需要一个类作为关键。该类有多个成员。我假设我的比较函数是正确的。我遵循严格的弱排序。问题是,它允许输入重复的键。

下面是我的代码。

#include <iostream>
#include <string.h>
#include <map>

class mapkey
{
public:
    std::string mInterface;
    std::string mDestination;
    int         mPrefixLen;
    std::string mNextHop;
    int         mMetric;

    mapkey() {}
   ~mapkey() {}
    mapkey(std::string a, std::string b, int c, std::string d, int e)
    {
      mInterface = a;
      mDestination = b;
      mPrefixLen = c;
      mNextHop = d;
      mMetric = e;
    }
};

struct mapcomp
{
  bool operator() (const mapkey left, const mapkey right);
};

bool mapcomp::operator() (const mapkey left, const mapkey right)
{
  if(strcmp(left.mInterface.c_str(), right.mInterface.c_str()) < 0)
    return true;
  if(strcmp(left.mInterface.c_str(), right.mInterface.c_str()) > 0)
    return false;

  if(strcmp(left.mDestination.c_str(), right.mDestination.c_str()) < 0)
    return true;
  if(strcmp(left.mDestination.c_str(), right.mDestination.c_str()) > 0)
    return false;

  if(strcmp(left.mNextHop.c_str(), right.mNextHop.c_str()) < 0)
    return true;
  if(strcmp(left.mNextHop.c_str(), right.mNextHop.c_str()) > 0)
    return false;

  if(left.mPrefixLen < right.mPrefixLen)
    return true;
  if(left.mPrefixLen > right.mPrefixLen)
    return false;

  if(left.mMetric < right.mMetric)
    return true;
  if(left.mMetric > right.mMetric)
    return false;
}

typedef std::map<mapkey, std::string, mapcomp> script_map;
script_map mm;

void print_map()
{
   script_map::const_iterator iter;
   for (iter = mm.begin(); iter != mm.end(); iter++)
   {
     std::cout << "value is - " << iter->second << std::endl;
   }
}

int main()
{
   mapkey test1("eth1", "50.60.70.80", 1, "90.10.20.30", 1);
   mm[test1] = "first";

   mapkey test2("eth1", "50.60.70.40", 1, "90.10.20.30", 1);
   mm[test2] = "second";

   mapkey test3("eth1", "50.60.70.20", 1, "90.10.20.30", 1);
   mm[test3] = "third";

   mapkey test4("eth1", "50.60.70.80", 1, "90.10.20.30", 1);
   mm[test4] = "fourth";

   print_map();

   return 0;
}

上面的程序,第一个和第四个键是一样的。当我打印地图时,输出如下

g++ --std=c++11 map.cpp

./a.out

值为 - 第三个

值为 - 秒

值是 - 第四

值是 - 第一

我错过了什么?第四个条目应该没有被添加。

【问题讨论】:

  • 所以,你的比较函数不正确。
  • 所有的 C 函数是什么? std::string 附带built in comparison operators。您可能还想使用std::tie
  • 你的编译器应该警告你比较可能没有返回值,如果对象相等就会发生这种情况。如果确实如此但您忽略了它,请停止忽略警告。

标签: c++ c++11 stdmap


【解决方案1】:

原因:你的比较功能坏了。

解决方案:使用惯用的 C++ 编写一个新的。

struct mapcomp
{
  bool operator() (mapkey const& l, mapkey const& r) {
      return 
           std::tie(l.mInterface, l.mDestination, l.mPrefixLen, l.mNextHop, l.mMetric) 
           <
           std::tie(r.mInterface, r.mDestination, r.mPrefixLen, r.mNextHop, r.mMetric)
      ;
  }
};
  • 我通过mapkey const&amp; 而不是mapkey 以避免复制。
  • 我使用元组比较和std::tie 从您的成员中生成元组。

您还应该从mapkey 中删除所有构造函数和析构函数。它们没有任何作用,因为您可以通过通用初始化来初始化成员。

我还会考虑将结构更改为您的班级的 operator&lt;(可能还有 operator==)的重载。 map 接受它而不通过任何其他比较器就足够了。

【讨论】:

  • 他们可能还想考虑切换到std::tuple,因为它为他们内置了比较功能。
  • @NathanOliver 这可能意味着编写自定义命名的访问标签。三个字符串和两个整数,很容易混淆。
  • 是的,这只是一个建议。
  • 使用std::tie的好主意!第一次看到std::tie应用于地图对比功能,非常合身。它真的是惯用的吗?
  • @anatolyg 我相信是的。我自己还没有发明它,但遗憾的是我也不知道该归功于谁。
【解决方案2】:

从这里开始:

if(strcmp(left.mInterface.c_str(), right.mInterface.c_str()) < 0)
    return true;
if(strcmp(left.mInterface.c_str(), right.mInterface.c_str()) > 0)
    return false;

strcmp() 在字符串相等时返回零且仅返回零。

然后看第一行:它在所有其他成员有机会进行比较之前返回true

【讨论】:

  • std::string 提供 operator==() 为什么不使用它而不是 C 的 strcmp()
  • std::string 还提供operator&lt;()operator&gt;()
  • @AlejandroDíaz, SimonKraemer:本质上。我只是认为 OP 可能是一个学生——然后最好自己找到更多的东西 =)
【解决方案3】:

您的 mapcomp 方法并非在所有情况下都返回值。您需要在函数末尾返回 false 以表明项目相等。

我建议使用内置字符串

bool mapcomp::operator() (const mapkey& left, const mapkey& right)
{
  if(left.mInterface < right.mInterface) return true;
  if(left.mInterface > right.mInterface) return false;

  if(left.mDestination < right.mDestination) return true;
  if(left.mDestination > right.mDestination) return false;

  if(left.mNextHop < right.mNextHop) return true;
  if(left.mNextHop > right.mNextHop) return false;

  if(left.mPrefixLen < right.mPrefixLen) return true;
  if(left.mPrefixLen > right.mPrefixLen) return false;

  if(left.mMetric < right.mMetric) return true;
  if(left.mMetric > right.mMetric) return false;

  return false; // items are equal  
}

【讨论】:

    【解决方案4】:

    在你可以使用之前的 C++

    bool mapcomp::operator() (const mapkey left, const mapkey right)
    {
        if (left.mInterface != right.mInterface)        return left.mInterface < right.mInterface;
        if (left.mDestination != right.mDestination)    return left.mDestination < right.mDestination;
        if (left.mNextHop != right.mNextHop)            return left.mNextHop < right.mNextHop;
        if (left.mPrefixLen != right.mPrefixLen)        return left.mPrefixLen < right.mPrefixLen;
        if (left.mMetric != right.mMetric)              return left.mMetric < right.mMetric;
        return false; //equal != less
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-08-31
      • 1970-01-01
      • 1970-01-01
      • 2016-06-09
      • 2013-08-22
      • 1970-01-01
      • 1970-01-01
      • 2022-01-21
      相关资源
      最近更新 更多