号より小さいリロードで注意すべき問題-strict weak ordering



これは今日プログラムを書く中で出会った2つの奇妙な問題です.私の
IDE
はい
VC++2005 ExpressiEdition
.
最初の質問は
map
のです.あまり話さないで、以下
20
マルチライン
C++
コードは私が直面した問題を再現しました.
#include

#include

using
namespace std;
 
struct
S {
     int x, y;
     S(int xx, int yy): x(xx), y(yy) {}
     bool operator <(const S& s) const {
         return x < s.x && y < s.y;
     }
};
 
map ms;
 
int
main() {
     ms.insert(map::value_type(S(31, 41), 59));
 
     S test(31, 59);
     if (ms.find(test) != ms.end()) {
         cout << "Find the value: "<< ms[test] << endl;
     } else {
         cout << "Find Failure/n";
     }
     return 0;
}
使用
VC++6.0
,
VC++2005 Express Edition, VC++2005 command line compiler(
コンパイルオプションなし
)
,
g++
テストの結果は同じで、最後に出力します.
Find the value: 59
この問題は比較的隠れている.複数のコンパイラのテスト結果が同じであることは、コンパイラバージョンに関連する問題ではないことを示しています.ダイレクトデバッグアクセス
find
関数は次のことを示します.
     iterator find(const key_type& _Keyval)
         {    //find an element in mutable sequence that matches _Keyval
         iterator _Where = lower_bound(_Keyval);
         return (_Where == end()
              || _DEBUG_LT_PRED(this ->comp,
                   _Keyval, _Key(_Where._Mynode()))
                       ? end() : _Where);
         }
デバッグはいくつかありますが
STL
内部の細部は、しかし全体の実現の構想はやはり見ることができます.にある
find
関数では、
lower_bound
戻り値はノードです
(31, 41)
.トレースイン、呼び出しの検出
_DEBUG_LT_PRED
の定義は次のとおりです.
#define
_DEBUG_LT_PRED(pred, x, y)   _Debug_lt_pred(pred, x, y, __FILEW__, __LINE__)
 
template
inline
     bool __CLRCALL_OR_CDECL _Debug_lt_pred(_Pr _Pred, const _Ty1& _Left, const _Ty2& _Right,
         const wchar_t *_Where, unsigned int _Line)
     {    //test if _Pred(_Left, _Right) and _Pred is strict weak ordering
     if (!_Pred(_Left, _Right))
         return (false );
     else if (_Pred(_Right, _Left))
         _DEBUG_ERROR2("invalid operator<", _Where, _Line);
     return (true );
     }
(
注意:説明[ちゅうしゃく:せつめい]
_Debug_lt_pred
関数には3つのリロードバージョンがあり、それぞれパラメータ
_Left, _Right

const
性質的に、これらのコードを見て多くのことを学ぶことができます.また、これらのコードを静的に見て自分のプログラムのエラーを解析すると、大量のリロード関数があるため、静的解析ではどの関数が呼び出されたのかを自分で判断することが難しく、動的デバッグでは一歩前進することができます.
)
この関数のコードから大体問題点がわかります.ここの
_Pred
パラメータは自分で
struct
に定義されている
operator <
を選択します.
_Pred

value
はい
{lessthan }
,
type
はい
std::less

しかし、ここにはもっと大きな発見があります.
strict weak ordering!!!
自分自身
C++
基礎が浅いので、これは新しい発見で、すぐに
google
ちょっと
”strict weak ordering”
このキーワードは、やはり大量の特集リンクを発見!ひとまずこのテーマを置いておく.問題の推測はきっと
operator <
この関数は、自分の
operator <
定義:
{31, 41} < {31, 59}
戻り値Yes
false
,
{31, 59} < {31, 41}
の戻り値も
false
では、この2つの比較から結論を出すことができます.
{31, 41} == {31, 59} !!!
これもプログラムの実行が望ましくない結果を返すのも無理はない.
しかし、これは推測にすぎません.デバッグを続けて、見つけられるかどうか見てみましょう.
_Pred
関数の真の姿.コンパイラから見ると
_Pred

type
はい
std::less

で、
MSDN
で行ないます.
less
はい
STL
のテンプレートクラスです.
MSDN
で参照できます..
less
less template<class T>
struct less : public binary_function <T, T, bool> {
bool operator() (const T& x, const T& y) const;
};
The template class defines its member function as returning x < y . The member function defines a total ordering , even if T is an object pointer type.
デバッグしてアクセスを追跡します
_Pred
関数では、次のように定義されています.
template

     struct less
         : public binary_function<_Ty, _Ty, bool >
     {    //functor for operator<
     bool operator ()(const _Ty& _Left, const _Ty& _Right) const
         {    //apply operator< to operands
         return (_Left < _Right);
         }
     };
最終的に比較します
_Left
および
_Right
に呼び出されたのは
struct
S
で定義した
operator <
.
これで問題の真相が明らかになった.2つのトピックが残っています.1つは
strict weak ordering
あ、もう一つは
STL
のいくつかの実現方法は、以上がデバッグ過程を追跡して沿道で見たものを機械的に記録しただけなので、本当の理解ではありません.
 
今日はもう一つの問題に直面しました
STL
タブで行います.
sort
関数の問題、この問題はただ
VC++ 2005 Express Edition
に表示され、コマンドラインで使用されます.
cl.exe
オプションなしで接続をコンパイルする場合は通常、
g++
正常です.問題の表現は、プログラムが実行中に異常が発生したことです.情報は次のとおりです.
”invalid operator <”
.この問題はデバッグを再現しません.その解決方法は次のアドレスを参照してください.
http://support.microsoft.com/kb/949171
 
strict weak ordering
数学の用語で、さっき与えられたこのアドレスには
strict weak ordering
の簡明な解釈を貼ってください.
The STL algorithms for stable_sort ( ) and sort() require the binary predicate to be strict weak ordering. For example: · Strict: pred (X, X) is always false. · Weak: If ! pred (X, Y) && !pred (Y, X), X==Y. · Ordering: If pred (X, Y) && pred (Y, Z), then pred (X, Z).