C++ 排序会崩溃,而stable_sort不会,但两者都不起作用

c++ sort will crash while stable_sort won't, but both take no effect

本文关键字:不会 sort 不起作用 两者都 stable 排序 崩溃 C++      更新时间:2023-10-16
    class AP {
public:
  AP():
    BSSID(""),
    SSID(""),
    PASSWORD(""),
    LinkStatus(eWifiAPLinkStatus_UnConnected),
    AuthType(eWifiSecurityType_Unknown),
    SignalLevel(eWifiAPSignalStrength_level0),
    Remembered(eWifiRememberedAP_Unknown)  {}
  AP(std::string ssid, WifiSecurityType authType, std::string password);
  AP(std::string bssid, std::string ssid, WifiAPSignalStrength sigLev,WifiSecurityType authType,int SignalDB);
  AP(std::string ssid, WifiAPSignalStrength sigLev,WifiSecurityType authType,int SignalDB);
  AP &operator=(const AP &);
  AP(const AP &);
  std::string BSSID;
  std::string SSID;
  std::string PASSWORD;
  WifiAPLinkStatus LinkStatus;
  WifiSecurityType AuthType; /// PasswordProtected is defined in patac's Proto
  WifiAPSignalStrength SignalLevel;
  int SignalDB;
  WifiRememberedAP Remembered;
  std::string getBSSID() const;
  void setBSSID(const std::string &value);
  std::string getSSID() const;
  void setSSID(const std::string &value);
  std::string getPASSWORD() const;
  void setPASSWORD(const std::string &value);
  WifiAPLinkStatus getLinkStatus() const;
  void setLinkStatus(const WifiAPLinkStatus &value);
  WifiSecurityType getAuthType() const;
  void setAuthType(const WifiSecurityType &value);
  WifiAPSignalStrength getSignalLevel() const;
  void setSignalLevel(const WifiAPSignalStrength &value);
  WifiRememberedAP getRemembered() const;
  void setRemembered(const WifiRememberedAP &value);
  int getSignalDB() const;
  void setSignalDB(int value);
};
std::ostream& operator<<(std::ostream &output, const AP &D);

std::向量使用scanap;

AP是一个类,它有一个getter函数(在其他函数中)getSignalDB返回一个int:

我的问题是:
 std::sort(ScanAps.begin(),ScanAps.end(),
               [](const AP &m, const AP &n)-> bool{return
      m.getSignalDB() < n.getSignalDB(); });

…有时会使整个过程崩溃,但是

 std::stable_sort(ScanAps.begin(),ScanAps.end(),
               [](const AP &m, const AP &n)-> bool{return
      m.getSignalDB() < n.getSignalDB(); });

…不会。这两种排序都不起作用:

PRINT_ELEMENTS(ScanAps,"AFTER SORT ScanAps IS :n");

打印结果是(当不崩溃时,注意最后一个颜色):

BSSID:fc:8b:97:5c:c1:fd SSID:dlink  PASSWORD:  LINKSTAUS:2  SignalDB:-57
BSSID:cc:d5:39:5d:d4:b0 SSID:YFVEGROUP  PASSWORD:  LINKSTAUS:2  SignalDB:-70
BSSID:fc:8b:97:5c:e7:3c SSID:dlink_mwang  PASSWORD:  LINKSTAUS:2  SignalDB:-73
BSSID:5c:63:bf:73:e9:6a SSID:eagle_link  PASSWORD:  LINKSTAUS:2  SignalDB:-46
BSSID:cc:d5:39:9e:30:b0 SSID:YFVEGROUP  PASSWORD:  LINKSTAUS:2  SignalDB:-49
BSSID:00:36:76:1c:ab:3f SSID:360WiFi-AB3F  PASSWORD:  LINKSTAUS:2  SignalDB:-54
BSSID:fc:8b:97:5c:bb:40 SSID:dlink_wj  PASSWORD:  LINKSTAUS:2  SignalDB:-57
BSSID:fc:8b:97:5c:e8:9f SSID:ARCH-HP_Network  PASSWORD:  LINKSTAUS:2  SignalDB:-62
BSSID:fc:8b:97:5c:d8:3c SSID:dlink_sammu  PASSWORD:  LINKSTAUS:2  SignalDB:-71
BSSID:cc:d5:39:9e:30:be SSID:YFVEGUEST  PASSWORD:  LINKSTAUS:2  SignalDB:-58
BSSID:cc:d5:39:e3:3c:00 SSID:YFVEGROUP  PASSWORD:  LINKSTAUS:2  SignalDB:-62
BSSID:cc:d5:39:9e:30:bf SSID:YFVEGROUP  PASSWORD:  LINKSTAUS:2  SignalDB:-75
BSSID:98:ff:d0:b4:07:2a SSID:Lenovo A375e  PASSWORD:  LINKSTAUS:2  SignalDB:-62
BSSID:fc:8b:97:5c:df:0d SSID:Matthew  PASSWORD:  LINKSTAUS:2  SignalDB:-80
BSSID:cc:d5:39:e3:3c:01 SSID:YFVEGUEST  PASSWORD:  LINKSTAUS:2  SignalDB:-73
BSSID:3c:df:bd:dd:fd:d3 SSID:Alex3G  PASSWORD:  LINKSTAUS:2  SignalDB:-67
BSSID:b8:a3:86:87:fe:b6 SSID:D-Link_DIR-600A  PASSWORD:  LINKSTAUS:2  SignalDB:-82
BSSID:cc:d5:39:9e:b0:b0 SSID:YFVEGROUP  PASSWORD:  LINKSTAUS:2  SignalDB:-94
BSSID:fc:8b:97:5c:c6:03 SSID:dlink_xlv1  PASSWORD:  LINKSTAUS:2  SignalDB:-82
BSSID:cc:d5:39:9e:b0:b1 SSID:YFVEGUEST  PASSWORD:  LINKSTAUS:2  SignalDB:-94

从评论来看,问题似乎是在赋值操作符中缺少SignalDB的赋值。这个缺失的赋值可以很容易地解释为什么这两种排序算法实际上都不能对值进行排序:那里有一些随机值,这些值会随着值的变化而不断变化。

顺便说一下,它也解释了为什么std::sort()崩溃而std::merge_sort()没有,虽然肯定不能保证std::merge_sort()不会崩溃:排序标准必须是严格的弱顺序和被排序的值必须是可复制的。如果这些约束不成立,任一算法的行为都是未定义的。copyable约束规定不能将值的副本与原始值区分开来,并且可以完全互换使用。如果被比较的值没有被真正复制,则不是这种情况。

崩溃与非崩溃的区别是基于排序的实际实现方式。请注意,这两种排序都不能保证崩溃,因为在这两种情况下行为都是未定义的。然而,std::stable_sort()使用的算法更有可能产生错误的结果,而不是崩溃。为了最小化std::sort()内部循环中的操作,在序列开始时使用哨兵:以战略方式确保足够小的元素最终出现在序列的正确位置。这样,内部循环只需要比较值,而不是验证值是否仍然在范围内:由于内部循环中使用了哨兵搜索,它永远不会尝试移动序列。然而,如果最小的元素得到一个或多或少的随机值,那么它可能根本不是最小的元素,并且"哨兵"不是真正的哨兵,使搜索徘徊到查找它不打算查找的字段。

要获得更详细的解释,您可能想要观看Stepanov关于高效组件编程的讲座的最后两个视频(尽管讲座非常慢,但我认为观看所有这些讲座实际上都是有价值的)。我想具体的问题在上个视频的倒数第二节讨论过,但我记不清了。讨论的重点是排序不是严格的弱顺序,但如果副本不是真正的副本,效果是一样的。