第19条:平等と同等の違いを理解する
連想コンテナセット/マルチセット、マップ/マルチマップには、コンテナ要素の順序付けルールを決定するために使用されるテンプレートパラメータがあります。標準タイプlessが使用され、セット、マップなどの要素のみが使用されます。同等性を定義します。
テンプレートクラスマップの形式は次のとおりです。
std::map
template < class Key, // map::key_type
class T, // map::mapped_type
class Compare = less<Key>, // map::key_compare
class Alloc = allocator<pair<const Key,T> > // map::allocator_type
> class map;
標準のテンプレートクラスセットの形式は次のとおりです。
std::set
template < class T, // set::key_type/value_type
class Compare = less<T>, // set::key_compare/value_compare
class Alloc = allocator<T> // set::allocator_type
> class set;
同等性は次のように定義されます。素人の用語では、aはbの前になく、bはaの前にありませんが、同等性と同じではありません。等しい場合、2つのコンテナの要素は同等である可能性がありますが、等しくなければならない
!comp(a,b) && !comp(b,a))
例、文字列間の大文字と小文字を区別しない比較の実装(少し低い場合があります、文字列はコピーされます、これは無視するポイントではありません)
// string不区分大小写的比较
struct CIStringCompare : public std::binary_function<string, string, bool> {
bool operator()(const string &lhs, const string &rhs) const {
string lstr(lhs);
std::transform(lhs.cbegin(), lhs.cend(), lstr.begin(), tolower);
string rstr(rhs);
std::transform(rhs.cbegin(), rhs.cend(), rstr.begin(), tolower);
return lstr < rstr;
}
};
void test_19() {
set<string, CIStringCompare> ciss; // 不区分大小写的字符串集合
ciss.insert("Persephone"); // 显然,这两个字符串不相等,但是根据我们对排序规则的定义,它们是等价的
ciss.insert("persephone");
std::for_each(ciss.cbegin(), ciss.cend(), [](const string &str) { std::cout << str << std::endl; });
return;
}
項目20:ポインターを含む連想コンテナーの比較タイプを指定します
文字列*を含むセットコンテナを定義し、いくつかの動物の名前を1つずつセットに挿入してから、以下に示すように1つずつ印刷するとします。そうです、あなたは孤独を印刷しました。文字列*である要素。文字列を出力するには、ポインタの内容を取得するために*を追加する必要があります。
void test_20() {
set<string *> ssp;
ssp.insert(new string("anteater"));
ssp.insert(new string("wombat"));
ssp.insert(new string("lemur"));
ssp.insert(new string("penguin"));
for(auto iter = ssp.cbegin(); iter != ssp.cend(); ++iter) {
std::cout << *iter << std::endl;
}
return;
}
输出:
0x3a5170
0x3a5220
0x3a52d0
0x3a5380
変更後は正常です
std::cout << **iter << std::endl;
输出:
anteater
wombat
lemur
penguin
上記のどれも重要ではありません。コンテナ要素はポインタであり、デフォルトではポインタの並べ替えが少ないため、文字列がルールに従って並べ替えられない理由に気づきましたか。文字列の問題なので、この句のコアは次のようになります。ポインタ用に書かれていますか?以下に示すように、あなた自身の比較タイプを見つけてください。
// string*比较
struct StrPtrCompare : public std::binary_function<string *, string *, bool> {
bool operator()(const string *lhs, const string *rhs) const {
return *lhs < *rhs;
}
};
void test_20() {
set<string *, StrPtrCompare> ssp;
ssp.insert(new string("anteater"));
ssp.insert(new string("wombat"));
ssp.insert(new string("lemur"));
ssp.insert(new string("penguin"));
for (auto iter = ssp.cbegin(); iter != ssp.cend(); ++iter) {
std::cout << **iter << std::endl;
}
return;
}
输出:
anteater
lemur
penguin
wombat
ちょっと待ってください、まだ終わっていません。実際に新しい文字列を配列に直接挿入します。メモリを自分で管理してから、1つずつ削除して解放しますか?いいえ、C ++ 11はスマートポインタを提供します
// std::shared_ptr<string>比较
struct SharedPtrCompare : public std::binary_function<std::shared_ptr<string>, std::shared_ptr<string>, bool> {
bool operator()(const std::shared_ptr<string> &lhs, const std::shared_ptr<string> &rhs) const {
return *lhs < *rhs;
}
};
void test_20() {
// 智能指针
set<std::shared_ptr<string>, SharedPtrCompare> sSharedp;
sSharedp.insert(std::make_shared<string>("anteater"));
sSharedp.insert(std::make_shared<string>("wombat"));
sSharedp.insert(std::make_shared<string>("lemur"));
sSharedp.insert(std::make_shared<string>("penguin"));
for (auto iter = sSharedp.cbegin(); iter != sSharedp.cend(); ++iter) {
std::cout << **iter << std::endl;
}
return;
}
输出:
anteater
lemur
penguin
wombat
最後に、テンプレートを定義するのは良くありませんか?なぜ各タイプの比較タイプを定義するのですか?
// 为指针、智能指针定义的通用比较模板类
struct DereferenceLess {
template<typename PtrType>
bool operator()(PtrType p1, PtrType p2) const {
return *p1 < *p2;
}
};
void test_20() {
// 普通指针
// set<string *, StrPtrCompare> ssp;
set<string *, DereferenceLess> ssp;
ssp.insert(new string("anteater"));
ssp.insert(new string("wombat"));
ssp.insert(new string("lemur"));
ssp.insert(new string("penguin"));
for (auto iter = ssp.cbegin(); iter != ssp.cend(); ++iter) {
std::cout << **iter << std::endl;
}
// 智能指针
// set<std::shared_ptr<string>, SharedPtrCompare> sSharedp;
set<std::shared_ptr<string>, DereferenceLess> sSharedp;
sSharedp.insert(std::make_shared<string>("anteater"));
sSharedp.insert(std::make_shared<string>("wombat"));
sSharedp.insert(std::make_shared<string>("lemur"));
sSharedp.insert(std::make_shared<string>("penguin"));
for (auto iter = sSharedp.cbegin(); iter != sSharedp.cend(); ++iter) {
std::cout << **iter << std::endl;
}
return;
}
输出:
anteater
lemur
penguin
wombat
anteater
lemur
penguin
wombat
参照:「EffectiveSTLChineseEdition」の第3章