2017-10-10 15 views
4

Le code suivant génère une erreur de segmentation lorsqu'il est compilé avec GCC 6.1.0. Étrangement, l'erreur est cohérente, mais ne se produit pas avec des tailles plus petites ou des expressions de comparaison légèrement différentes. Est-ce que vous avez une idée pourquoi?Comportement erratique du tri std :: de GCC avec lambda

#include <vector> 
#include <algorithm> 
#include <iostream> 
int main() { 
    int n = 1000; 
    std::vector<std::pair<double, double>> vec; 
    for(int i = 0; i < n; i++) { 
     vec.push_back(std::make_pair<double, double>((7*i)%3, (3*i)%5)); 
    } 
    std::sort(vec.begin(), vec.end(), [](std::pair<double, double> const & p1, std::pair<double, double> const & p2) {return (p1.first < p2.first) || ((p1.first==p2.first)&& (p1.second <= p2.second));}); 
    return 0; 
} 
+0

Vous devriez savoir que si tout ce que vous voulez est une comparaison lexicogrphique, alors 'std :: pair' le fait déjà sans intervention de votre part. – StoryTeller

+0

@StoryTeller Merci pour le conseil. Mais ce qui me dérange vraiment en ce moment, c'est la source de la faute de segmentation! –

+5

La source est dans votre comparaison n'induisant pas une relation d'ordre correcte. Le code a un comportement indéfini à cause de cela. – StoryTeller

Répondre

13

Essayez de changer

(p1.second <= p2.second) 

avec

(p1.second < p2.second) 

Je veux dire ... std::sort() besoin d'un comparateur qui retourne true ssi (si et seulement si) le premier argument (p1) est strictement inférieure à la seconde (p2). C'est-à-dire: doit retourner false lorsque p1 est égal à p2.

Si votre test est

(p1.first < p2.first) 
|| ((p1.first==p2.first)&& (p1.second <= p2.second)) 

vous obtenir true aussi quand p1 est égal à p2.

Avec un comparateur qui retourne true quand p1 est égal à p2 ... si je ne me trompe pas le comportement est indéfini si un « comportement erratique » (et une erreur de segmentation aussi) est tout à fait compréhensible.

11

Le problème ici est que votre lambda ne répond pas aux exigences de la norme pour Compare, qui nécessite une stricte faible commande:

  • stricte implique que !comp(x, x) doit être true pour chaque x en la séquence, ce qui n'est pas le cas pour votre comparateur personnalisé (lambda) depuis comp(x, x) == true pour chaque x dans votre cas (x.first == x.first && x.second <= x.second).

Vous devez soit modifier p1.second <= p2.second-p1.second < p2.second, ou utiliser l'opérateur de comparaison standard pour std::pair:

std::sort(vec.begin(), vec.end()); 
2

libstdC++ a un debug mode qui peut être activé en définissant la macro _GLIBCXX_DEBUG.

$ g++-6 b.cc -D_GLIBCXX_DEBUG && ./a.out 
/usr/include/c++/6/bits/stl_algo.h:4737: 
Error: comparison doesn't meet irreflexive requirements, assert(!(a < a)). 

Objects involved in the operation: 
    instance "functor" @ 0x0x7ffe48ba5a20 { 
     type = main::{lambda(std::pair<double, double> const&, std::pair<double, double> const&)#1}; 
    } 
    iterator::value_type "ordered type" { 
     type = std::pair<double, double>; 
    }