2014-10-08 14 views
9

Tôi có mã sau để kiểm tra con trỏ thông minh làm khóa cho std::map, tôi chạy mã trên Mac và Linux, nhưng tôi quan sát đầu ra khác nhau, có phải là lỗi hoặc tôi đã làm gì sai?Con trỏ thông minh làm khóa bản đồ

#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; 
} 

Trên Mac:

[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 

Trên Linux:

[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, các 'nhà điều hành thứ hai <' không cần phải là một người bạn, nó chỉ có thể là 'return * lhs <* rhs;' – o11c

+0

@ o11c, vâng, nhưng sự thay đổi không tạo ra sự khác biệt nào. – neevek

+0

Có thể liên quan: http://stackoverflow.com/questions/11115265/clang-stdshared-ptr-and-stdless-operator –

Trả lời

8

GCC là đúng (trên Mac như bạn thấy g++ là trong thực tế kêu vang): std::map sử dụng std::less<T> để so sánh các phím. Điều đó lần lượt gọi operator < trên các đối số, nhưng tra cứu được thực hiện đầu tiên trong namespace std, do đó, nó tìm thấy việc thực hiện mặc định cho shared_ptr, so sánh con trỏ nội bộ. Để thực hiện việc này, bạn phải chuyên std::less cho shared_ptr<Dog>:

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. Thực tế thú vị là nếu nó nằm ngoài không gian tên 'std', nó sẽ làm việc theo cách khác - toán tử' của ' Angew

+0

Cảm ơn câu trả lời nhanh chóng và giải thích rõ ràng, nó hoạt động! – neevek

2

Giá trị mặc định Compare đối tượng của std::mapstd::less<Key>, đó là std::shared_ptr<Dog> trong trường hợp của bạn. Vì vậy, nó sẽ cho thực hiện std::less< std::shared_ptr<Dog> >, và nó chỉ so sánh địa chỉ con trỏ.

Để xác định đối tượng Compare, bạn chỉ có thể xác định nó một mình và sử dụng nó trong map

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

Sau đó

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; 

đầu ra map size: 3

Các vấn đề liên quan