【问题标题】:std::map<struct,struct>::find is not finding a match, but if i loop thru begin() to end() i see the match right therestd::map<struct,struct>::find 没有找到匹配项,但是如果我通过 begin() 循环到 end() 我会在那里看到匹配项
【发布时间】:2020-07-15 18:23:19
【问题描述】:
struct chainout {
    LONG cl;
    std::string cs;
    bool operator<(const chainout&o)const {
      return cl < o.cl || cs < o.cs;
    }
  } ;
  struct chainin{
    std::string tm;
    std::string tdi;
    short mss;
    LONG pinid;
    bool operator<(const chainin&o)const {
      return  mss < o.mss || pinid < o.pinid || tm<o.tm; //no tdi right now it's always empty
    }
  };
  std::map   <chainin,chainout> chainmap;
  std::map<chainin,chainout>::iterator it;
  chainin ci;
  chainout co;


 string FADEDevicePinInfo::getNetAtPinIdTmTidMss (const LONG p,const string tm, const string tid,const LONG mss){

  ci.tm=tm;
//  ci.tdi=tid;
  ci.tdi="";
  ci.mss=(short)mss;
  ci.pinid=p;
  for (it=chainmap.begin();it!=chainmap.end();it++){
    if(it->first.pinid==ci.pinid && it->first.tm==ci.tm&&it->first.mss==ci.mss && it->first.tdi==ci.tdi){
      cout << "BDEBUG: found p["; cout<<it->first.pinid; cout<<"] tm["; cout<<it->first.tm.c_str();cout<<"] mss[";cout<<it->first.mss;cout<<"] : ";cout<<it->second.chainSignal.c_str();cout<<endl;
    }
  }
  it=chainmap.find(ci);
  if(it == chainmap.end()){
    MSG(SEV_T,("no pin data found for pin[%ld]/tm[%s]/tdi[%s]/mss[%ld]",ci.pinid,ci.tm.c_str(),ci.tdi.c_str(),ci.mss));
  }
  return it->second.cs;
}

这既打印成功找到的行,然后由于 map::find 未返回匹配项而引发 sev_t 错误。我做错了什么?

我通过

【问题讨论】:

  • 小测验:你必须chainouts,一个有cl=3cs="B",另一个有cl=4cs="A"。哪一个比另一个少?您的&lt; 将得出结论,其中任何一个都小于另一个。正如斯波克先生所说:这不合逻辑。正如您所观察到的,此 &lt; 运算符无法实现严格的弱排序,这会导致未定义的行为和 demons flying out of your nose

标签: c++ string dictionary struct find


【解决方案1】:

如 cmets 中所述,您的比较运算符很糟糕。如果您不知道对象应该按什么顺序排序,那么 std::map 或任何其他排序容器也不知道。

当您有多个要比较的东西时,考虑确定哪个最重要,并使用 std::tie 来比较它们,如下所示:

#include <string>
#include <iostream>

struct chainout {
    int cl;
    std::string cs;
    bool operator<(const chainout&o)const {
        return std::tie(cl, cs) < std::tie(o.cl, o.cs);
    }
};

int main(){
    chainout a{ 1, "b" };
    chainout b{ 2, "a" };
    std::cout << (a < b) << std::endl;
    std::cout << (b < a) << std::endl;
}

【讨论】:

    【解决方案2】:

    您的两个structs 的operator&lt; 实现不正确。

    std::map 需要密钥比较才能使用Strict Weak Ordering。这意味着当你的结构想要比较多个字段时,他们需要比较后面的字段only,而前面的字段比较相等。但是您没有检查这种情况。如果一个实例中的 any 字段比较小于另一个实例中的相应字段,则返回 true,而不管其他字段是否相等(或缺少)。因此,您正在破坏 SWO,这会导致在std::map 的查找中未定义的行为

    试试这个:

    struct chainout {
        LONG cl;
        std::string cs;
        bool operator<(const chainout &o) const {
            /*
            if (cl < o.cl) return true;
            if (cl == o.cl) return (cs < o.cs);
            return false;
            */
            return (cl < o.cl) || ((cl == o.cl) && (cs < o.cs));
        }
    };
    
    struct chainin{
        std::string tm;
        std::string tdi;
        short mss;
        LONG pinid;
        bool operator<(const chainin &o) const {
            if (mss < o.mss) return true;
            if (mss == o.mss) {
                if (pinid < o.pinid) return true;
                if (pinid == o.pinid) return (tm < o.tm);
            }
            return false;
        }
    };
    

    实现此功能的更简单方法是改用std::tie(),它有自己的operator&lt; 为您处理此问题,例如:

    struct chainout {
        LONG cl;
        std::string cs;
        bool operator<(const chainout &o) const {
            return std::tie(cl, cs) < std::tie(o.cl, o.cs);
        }
    };
    
    struct chainin{
        std::string tm;
        std::string tdi;
        short mss;
        LONG pinid;
        bool operator<(const chainin &o) const {
            return std::tie(mss, pinid, tm) < std::tie(o.mss, o.pinid, o.tm);
        }
    };
    

    无论哪种方式,std::map::find() 应该按预期工作,例如:

    std::map<chainin, chainout> chainmap;
    
    string FADEDevicePinInfo::getNetAtPinIdTmTidMss (const LONG p, const string tm, const string tid, const LONG mss)
    {
        chainin ci;
        ci.tm = tm;
        //ci.tdi = tid;
        ci.tdi = "";
        ci.mss = (short) mss;
        ci.pinid = p;
    
        std::map<chainin, chainout>::iterator it = chainmap.find(ci);
        if (it != chainmap.end()) {
            cout << "BDEBUG: found"
                 << " p[" << it->first.pinid << "]"
                 << " tm[" << it->first.tm << "]"
                 << " mss[" << it->first.mss << "]"
                 << " : " << it->second.cs
                 << endl;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-30
      • 2022-11-20
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多