【问题标题】:c++ sort will crash while stable_sort won't, but both take no effectc++ sort 会崩溃,而 stable_sort 不会,但两者都不起作用
【发布时间】:2014-05-04 05:46:09
【问题描述】:
    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::vector ScanAps;

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

【问题讨论】:

  • 你没有显示“AP” - 没有办法回答这个问题。
  • 您也没有显示 n 和 m 的分配位置。我们应该猜测吗?
  • 罪魁祸首很可能是AP的拷贝构造函数。
  • @o_weisman m 和 n 由 lambda 分配。我说的对吗?
  • @RSahu 为什么?我可以按 SSID 等其他字段排序,它可以工作。

标签: c++ sorting stl lambda crash


【解决方案1】:

从评论看来,问题在于赋值运算符中缺少SignalDB 的赋值。这个缺失的赋值很容易解释为什么这两种排序算法都不会真正对值进行排序:那里有一些随机值,这些值会随着值不断变化。

顺便说一句,它还解释了为什么std::sort() 崩溃而std::merge_sort() 不会崩溃,尽管不能保证std::merge_sort() 不会崩溃:排序标准必须是Strict Weak Order,并且被排序的值有是可复制的。如果这些约束不成立,则任一算法的行为都是未定义的。可复制约束指出,值的副本无法与原始值区分开来,并且可以完全互换使用。如果被比较的值没有被真正复制,则情况并非如此。

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

如需更详细的解释,您可能想观看Stepanov's lectures on Efficient Programming with Components 的最后两个视频(虽然讲座有点慢,但我认为观看所有这些视频实际上是有价值的)。我认为倒数第二个视频中讨论了具体问题,但我不记得确切。讨论的重点是排序不是严格的弱排序,但如果副本不是真正的副本,效果是一样的。

【讨论】:

  • 我接受作为答案。但这太复杂了。我更喜欢有人告诉我 std::sort 如何使用赋值运算符。
  • @huskarwang: std::sort() 使用 swap() 交换价值。标准实现本质上就像void swap(T&amp; a, T&amp; b) { T tmp(a); a = b; b = tmp; }(实际实现也使用移动)。
猜你喜欢
  • 1970-01-01
  • 2018-12-11
  • 2015-01-04
  • 1970-01-01
  • 2021-05-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-03
相关资源
最近更新 更多