2014-10-08 19 views
9

Akıllı işaretçiyi std::map için anahtar olarak test etmek için aşağıdaki koda sahibim, Mac ve Linux'ta kodu çalıştırıyorum, ancak farklı çıktılar gözlemledim, bir hata mı, yoksa yanlış bir şey mi yaptım? std::map anahtarları karşılaştırmak için std::less<T> kullanır: Mac'teHarita tuşu olarak akıllı işaretçiler

#include <iostream> 
#include <memory> 
#include <string> 
#include <map> 

using namespace std; 

class Dog { 
public: 
    typedef shared_ptr<Dog> sptr; 

    Dog(const string &name) : name_(name) { } 

    friend bool operator<(const Dog &lhs, const Dog &rhs) { 
    cout << "Dog::operator< called" << endl; 
    return lhs.name_ < rhs.name_; 
    } 

    friend bool operator<(const sptr &lhs, const sptr &rhs) { 
    cout << "Dog::operator< sptr called" << endl; 
    return lhs->name_ < rhs->name_; 
    } 

private: 
    string name_; 
}; 

void test_raw_object_as_map_key() { 
    cout << "raw object as map key ============== " << endl; 
    map<Dog, int> m; 
    m[Dog("A")] = 1; 
    m[Dog("B")] = 2; 
    m[Dog("C")] = 3; 
    m[Dog("A")] = 4; 

    cout << "map size: " << m.size() << endl; 
} 

void test_smart_pointer_as_map_key() { 
    cout << "smart pointer as map key ============== " << endl; 

    map<Dog::sptr, int> m; 
    m[make_shared<Dog>("A")] = 1; 
    m[make_shared<Dog>("B")] = 2; 
    m[make_shared<Dog>("C")] = 3; 
    m[make_shared<Dog>("A")] = 4; 

    cout << "map size: " << m.size() << endl; 
} 

int main(int argc, const char *argv[]) { 
    test_raw_object_as_map_key(); 
    test_smart_pointer_as_map_key(); 
    return 0; 
} 

:

Linux'ta
[email protected]$ g++ --version 
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/usr/include/c++/4.2.1 
Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn) 
Target: x86_64-apple-darwin13.1.0 
Thread model: posix 

[email protected]$ ./a.out 
raw object as map key ============== 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
map size: 3 
smart pointer as map key ============== 
Dog::operator< sptr called 
Dog::operator< sptr called 
Dog::operator< sptr called 
Dog::operator< sptr called 
Dog::operator< sptr called 
Dog::operator< sptr called 
Dog::operator< sptr called 
Dog::operator< sptr called 
Dog::operator< sptr called 
map size: 3 

: (Eğer g++ aslında clang olduğu gördüğünüz gibi Mac'te)

[email protected]$ g++ --version 
g++ (Ubuntu 4.8.2-19ubuntu1) 4.8.2 
Copyright (C) 2013 Free Software Foundation, Inc. 
This is free software; see the source for copying conditions. There is NO 
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 

[email protected]$ ./a.out 
raw object as map key ============== 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
Dog::operator< called 
map size: 3 
smart pointer as map key ============== 
map size: 4 
+0

btw map size: 3 kendiniz tanımlamak ve sonra map

class MyCompare { public: bool operator() (const sptr& l, const sptr& r) { return *l < *r; // Invokes your Dog's operator < } }; 

onu kullanabilirsiniz bir arkadaş olmak zorunda değil, sadece dönebilir * lhs <* rhs; – o11c

+0

@ o11c, evet, ama değişiklik hiçbir fark yaratmaz. – neevek

+0

Muhtemelen ilgili: http://stackoverflow.com/questions/11115265/clang-stdshared-ptr-and-stdless-operator –

cevap

8

GCC haklı. Bu da argümanlarda operator <'u çağırır, ancak arama ilk olarak namespace std'da gerçekleştirilir, böylece shared_ptr için içsel işaretçileri karşılaştırarak varsayılan uygulamayı bulur. senin durumunda std::shared_ptr<Dog> olan std::map ait Compare nesne std::less<Key> olduğunu

namespace std { 
    template<> 
    struct less<shared_ptr<Dog>> { 
     bool operator() (const shared_ptr<Dog>& lhs, const shared_ptr<Dog>& rhs) { 
      return *lhs < *rhs; 
     } 
    }; 
} 
+0

+1. Eğlenceli gerçek şu ki, eğer isim std' ad alanının dışında olsaydı, diğer yoldan çalışırdı - OP'nin operatörü, bir şablon değil, “std :: operatörüdür”. – Angew

+0

Hızlı cevaplama ve net açıklama için teşekkürler, işe yarıyor! – neevek

2

varsayılan: Eğer shared_ptr<Dog> için std::less uzmanlaşmak zorunda bu işi yapmak için. Dolayısıyla, std::less< std::shared_ptr<Dog> > uygulamasına bakar ve yalnızca işaretçi adresini karşılaştırır.

Compare nesneyi belirtmek için, sadece `<, ikinci` operatörü

map<sptr, int, MyCompare> m; 
    m[make_shared<Dog>("A")] = 1; 
    m[make_shared<Dog>("B")] = 2; 
    m[make_shared<Dog>("C")] = 3; 
    m[make_shared<Dog>("A")] = 4; 

    cout << "map size: " << m.size() << endl; 

çıkışları