2017-08-30 3 views
1

Hier ist der Code:С ++: „ungültig Komparator“ behaupten

struct Payment 
{ 
    Payment(time_t time, float money) : mTime(time), mMoney(money) {} 
    bool operator==(const Payment& p) const // exact comparison 
    { 
     return mTime == p.mTime && mMoney == p.mMoney; 
    } 
    time_t mTime; 
    float mMoney; 
}; 

std::vector<Payment> payments; 

auto sortP = [](const Payment& p1, const Payment& p2) { return p1.mTime < p2.mTime || p1.mMoney <= p2.mMoney; }; 
std::sort(payments.begin(), payments.end(), sortP); 

std::sort (nicht immer, aber manchmal, wenn mTime von zwei Elementen nahe beieinander) ungültig Komparator hebt in Visual Studio 2015 behaupten Was stimmt nicht mit dem Code?
enter image description here

+1

'|| p1.mMoney <= p2.mMoney' sollte '|| sein ((p1.mTime == p2.mTime) && (p1.mMoney VTT

+1

Vergleichen von zwei Floats ist keine gute Idee, Floats sind nicht genau dargestellt, sie sind Annäherungen. Sie müssen vergleichen, dass die Differenz weniger als ein Delta ist. Aus demselben Grund ist es auch keine gute Idee, Geld in einen Float zu stecken. –

+0

@ VTT: Sie haben Recht, das ist die Lösung. Mach es eine Antwort, ich werde es akzeptieren. – deko

Antwort

1

|| p1.mMoney <= p2.mMoney sollte || ((p1.mTime == p2.mTime) && (p1.mMoney < p2.mMoney)) seine Ansonsten Vergleich zum Fall falsch sein wird, wenn p1.mTime größer als p2.mTime während p1.mMoney ist kleiner als p2.Money. Eine gute Praxis, um sicherzustellen, dass solche Mehrfeldkomparatoren eine strenge schwache Bestellanforderung erfüllen, besteht darin, Tests für alle möglichen lt/gt-Kombinationen von Feldern zu schreiben.

+5

Eine gute Übung ist die Verwendung von 'std :: tie' – Slava

3

Das Problem ist mit der Implementierung von . Es erfüllt nicht die streng schwachen Bestellkriterien. Lesen Sie die Details unter http://www.sgi.com/tech/stl/StrictWeakOrdering.html.

Ich schlage vor, die folgende Änderung:

auto sortP = [](const Payment& p1, const Payment& p2) 
{ 
    // Order by mTime if they are not equal. 
    if (p1.mTime != p2.mTime) 
    { 
    return p1.mTime < p2.mTime; 
    } 

    // Otherwise, order by pMoney 
    return (p1.mMoney < p2.mMoney); // Use < not <= 
}; 

Sie können std::tie verwenden die Implementierung einfacher zu machen.

auto sortP = [](const Payment& p1, const Payment& p2) 
{ 
    return std::tie(p1.mTime, p1.mMoney) < std::tie(p2.mTime, p2.mMoney); 
}; 
+3

Mit 'std :: tie 'ist einfacher – Slava

+0

@Slava, natürlich. Danke für den Tipp. –

1

Mit c++11 Ihre Lambda-Komparator sollte wie folgt aussehen:

#include <tuple> 
... 
auto sortP = [](const Payment& p1, const Payment& p2) 
{ 
    return std::tie(p1.mTime, p1.mMoney) < std::tie(p2.mTime, p2.mMoney); 
};