2017-10-30 9 views
1

<演算子がC++でオーバーロードされている場合(たとえば、カスタム構造体をstd::setに挿入する場合)、実装は基底型の上にstrict weak orderでなければならないことを理解しています。std :: setと<Operator Overloadingの不思議な振る舞い?

structと実装について考えてみましょう。この実装では、厳密な弱いためではありませんが、コードがコンパイルされ、エラーを投げずに(私は厳密に弱いための要件を考えると、エラーをスローすることを期待する)を実行します:

#include <iostream> 
#include <set> 
using namespace std; 

struct Pixel { 
    int x; 
    int y; 
}; 

bool operator < (Pixel lhs, Pixel rhs){ 
    return lhs.x < rhs.x || lhs.y < rhs.y; 
}; 

int main(){ 
    set<Pixel> mySet; 

    Pixel *newPixelA = new Pixel; 
    newPixelA->x = 1; 
    newPixelA->y = 3; 

    Pixel *newPixelB = new Pixel; 
    newPixelB->x = 4; 
    newPixelB->y = 2; 

    mySet.insert(*newPixelA); 
    mySet.insert(*newPixelB); 

} 

はこれです期待される行動は?編集:Xcodeを使用します。

+6

定義されていない動作は未定義です。 「働くと思われる」は、未定義の動作の可能性のある表現の1つです。 –

+0

あなたの「見えるものは」実際にあなたが観察したものの正確な記述です。挿入のためにソースオブジェクトを動的に割り当てる理由も不明です。 – AnT

+0

2つ以上の項目で試してください。Visual Studioは、デバッグビルドですぐに例外をスローしました。 –

答えて

4

コンパイラは、operator<が厳密な弱い順序であるかどうかを判断する方法がありません。代わりに、これを必要とするstd::setが意味することは、それが厳密な弱い順序を与える場合にのみ正しく動作するということです。それはあなたが何か他のものを与えた場合に起こることを保証しません。

一般的に、何かが必要なときには、何かが起こることを確認することが、あなたの責任であるということです。そうした場合、コンパイラとライブラリは正しい結果を得ることができます。

1

コンパレータの要件が満たされている場合、標準によって期待される動作が保証されます。それ以外の場合は、実装とデータセットによって異なります。あなたの比較関数は、いくつかのデータセットで正しく動作するかもしれません(xが大きいほどxが大きいことを意味します)。でもaかかわら

a < b == true 
b < a == true 

:セットすでに存在する場合、それだけで価値aを挿入することを防ぐますのでbを重視、(数学の概念として)同等の要素が含まれており、std::set等価のための平等を意味することはできません、その結果、等しいかもしれないb

1

比較演算子が含まれている要素の厳密な弱い順序を実装する場合、std::setのオブジェクトは予測可能なパターンで順序付けられます。そうでない場合は、オブジェクトを反復処理するときに、最初に表示されるオブジェクトがstd::setにありません。

Pixel1の注文が正しく行われず、Pixel2の注文が正しく行われた次のサンプルプログラムを実行してください。 std::set<Pixel2>内のオブジェクトの順序は、挿入の順序とは無関係である

#include <iostream> 
#include <set> 

struct Pixel1 { 
    int x; 
    int y; 
}; 

bool operator < (Pixel1 lhs, Pixel1 rhs){ 
    return lhs.x < rhs.x || lhs.y < rhs.y; 
}; 

struct Pixel2 { 
    int x; 
    int y; 
}; 

bool operator < (Pixel2 lhs, Pixel2 rhs){ 
    if (lhs.x != rhs.x) 
    { 
     return (lhs.x < rhs.x); 
    } 
    return (lhs.y < rhs.y); 
}; 

template <typename Pixel> void print(std::set<Pixel> const& mySet) 
{ 
    for (Pixel p : mySet) 
    { 
     std::cout << "(" << p.x << ", " << p.y << ") "; 
    } 
    std::cout << std::endl; 
} 

template <typename Pixel> void test1() 
{ 
    std::set<Pixel> mySet; 

    Pixel pixelA = {2, 3}; 
    Pixel pixelB = {4, 2}; 
    Pixel pixelC = {4, 1}; 

    mySet.insert(pixelA); 
    mySet.insert(pixelB); 
    mySet.insert(pixelC); 

    print(mySet); 
} 

template <typename Pixel> void test2() 
{ 
    std::set<Pixel> mySet; 

    Pixel pixelA = {2, 3}; 
    Pixel pixelB = {4, 2}; 
    Pixel pixelC = {4, 1}; 

    mySet.insert(pixelB); 
    mySet.insert(pixelA); 
    mySet.insert(pixelC); 

    print(mySet); 
} 

int main() 
{ 
    std::cout << "Pixel1 ... \n"; 
    test1<Pixel1>(); 
    test2<Pixel1>(); 

    std::cout << "Pixel2 ... \n"; 
    test1<Pixel2>(); 
    test2<Pixel2>(); 
} 

出力

Pixel1 ... 
(4, 1) (4, 2) (2, 3) 
(4, 1) (2, 3) (4, 2) 
Pixel2 ... 
(2, 3) (4, 1) (4, 2) 
(2, 3) (4, 1) (4, 2) 

std::set<Pixel1>内のオブジェクトの順序は、挿入の順序に依存します。

関連する問題