2011-06-19 32 views
1

考慮下面的代碼C++:shared_ptr的爲unordered_set重點

#include <boost/unordered_set.hpp> 
#include <boost/shared_ptr.hpp> 
#include <boost/make_shared.hpp> 

int main() 
{ 
    boost::unordered_set<int> s; 
    s.insert(5); 
    s.insert(5); 
    // s.size() == 1 

    boost::unordered_set<boost::shared_ptr<int> > s2; 
    s2.insert(boost::make_shared<int>(5)); 
    s2.insert(boost::make_shared<int>(5)); 
    // s2.size() == 2 
} 

的問題是:S2的大小怎麼來的是2而不是1?我很確定它必須與散列函數有關。我試着看看助推器文檔,並沒有運氣玩哈希函數。

想法?

回答

5

make_shared分配新的int,並在其周圍包裝shared_ptr。這意味着你的兩個shared_ptr<int>指向不同的內存,並且由於你創建了一個鍵值爲指針值的散列表,它們是不同的鍵。

出於同樣的原因,這將導致一個大小爲2:

boost::unordered_set<int *> s3; 
s3.insert(new int(5)); 
s3.insert(new int(5)); 
assert(s3.size() == 2); 

對於您可以考慮shared_ptr s到行爲就像指針,包括比較,除了自動銷燬的大部分。

你可以定義自己的散列函數和比較謂詞,並把它們傳遞作爲模板參數unordered_map,雖然:

struct your_equality_predicate 
    : std::binary_function<boost::shared_ptr<int>, boost::shared_ptr<int>, bool> 
{ 
    bool operator()(boost::shared_ptr<int> i1, boost::shared_ptr<int> i2) const { 
     return *i1 == *i2; 
    } 
}; 

struct your_hash_function 
    : std::unary_function<boost::shared_ptr<int>, std::size_t> 
{ 
    std::size_t operator()(boost::shared_ptr<int> x) const { 
     return *x; // BAD hash function, replace with somethign better! 
    } 
}; 

boost::unordered_set<int, your_hash_function, your_equality_predicate> s4; 

然而,這可能有幾個原因是一個壞主意:

  1. 你有令人困惑的情況,其中x != ys4[x]s4[y]是相同的。
  2. 如果有人通過散列鍵更改指向的值,那麼您的散列將打破!那就是:

    boost::shared_ptr<int> tmp(new int(42)); 
    s4[tmp] = 42; 
    *tmp = 24; // UNDEFINED BEHAVIOR 
    
與散列函數

通常你想關鍵是不可改變的;無論以後會發生什麼,它總會比較相同。如果你使用的是指針,你通常希望指針的標識符是匹配的,如extra_info_hash[&some_object] = ...;無論some_object的成員是什麼,這通常都會映射到相同的散列值。在插入後鍵值不可變,實際上很容易這樣做,導致哈希中的未定義行爲。

+0

右鍵着,當然。所以我應該能夠通過使用(智能)指針來實現相同的語義?這意味着通過以某種特定方式定義哈希函數,大小應該是1而不是2.我該怎麼做? – Jay

+0

@Jay:更新了一個例子,並警告不要這樣做 – bdonlan

0

正如您發現的那樣,插入到s2中的兩個對象是不同的。

2

注意,在升壓< = 1.46.0,默認一個boost::shared_ptrhash_value是其布爾值,truefalse。 對於任何不是NULLshared_ptrhash_value評估爲1(一),如(bool)shared_ptr == true

換句話說,如果您正在使用Boost < = 1.46.0,那麼您將降級爲鏈接列表

這是固定在升壓1.47.0,見https://svn.boost.org/trac/boost/ticket/5216

如果使用std::shared_ptr,請定義自己的散列函數,或者使用boost/functional/hash/extensions.hpp從升壓> = 1.51.0