2013-05-13 44 views
-6

我使用C++ 11標準的代碼轉換的這個問題:C++ 11:轉換const int的*爲int *使用unordered_set ::推

#include<unordered_set> 
struct B 
{ 
    int x, y; 
}; 

class A 
{ 
    struct hash 
    { 
     std::size_t operator()(int* const a) const 
     { 
     return std::hash<int>()(*a); 
     } 
    }; 

    struct equal_to 
    { 
     std::size_t operator()(int* const a, int* const b) const 
     { 
     return std::equal_to<int>()(*a, *b); 
     } 
    }; 

    private: 
     std::unordered_set< int*, hash, equal_to > set; 

    public: 
     void push(const B& b) 
     { 
     set.insert(&b.x); 
     } 
}; 

任何人都知道這是爲什麼?我可以解決在「push」參數中刪除「const」修飾符的問題。但我不想要它,因爲參數「b」沒有被修改。

編輯:我簡化了代碼產生了一個未引用的地址。我做了一個結構B刪除它。

+0

這不是C11。 – 2013-05-13 19:02:23

+2

投票重新開放。問題出在'set.insert(&a)'中,其中'a'的類型爲'const int&'。 'a'的地址具有類型「指向const int的指針」,但是set對象正在尋找「指向(可修改)int」的指針。這種「常量」的混淆是相當普遍的,並且值得回答。 – 2013-05-13 19:06:47

+2

與你的問題無關,但你正在存儲一個對象的地址,該對象可能是你的設置中的一個臨時對象。一旦傳遞給'push'方法的'a'超出了範圍,那麼地址是無效的,並且如果它被引用(通過您的'equal_to'方法),則可能導致堆損壞或應用程序崩潰。 – pstrjds 2013-05-13 19:08:47

回答

2

set的鍵被聲明爲pointer-to-intint*。但這:

void push(const B& b) 
{ 
    set.insert(&b.x); 
} 

行經恆定int的地址,int const*,因此編譯錯誤。

去除參數中的const就解決了編譯器錯誤,如將使得密鑰類型的int const*,但是這兩種解決辦法:

  • 許可程序的其他部分,與非const訪問B實例傳遞給push(),更改設置中的關鍵之一的值,並打破了一套不變的:

    A a; 
    
    B b1{17, 22}; 
    B b2{30, 22}; 
    
    a.push(b1); 
    a.push(b2); 
    
    b1.x = 30; // set no longer contains unique keys. 
    
  • 介紹set的依賴上引用的對象的生命週期由b

    A a; 
    a.push({14, 23}); // a now contains a dangling pointer. 
    

最安全的解決方案是將一個int爲重點,見http://ideone.com/KrykZw在線演示(感謝bitmask徵求意見)。


可能的解決方案:

  1. 動態複製b.x。或者,
  2. 使用int const*作爲關鍵。或者最好(避免明確的動態分配),
  3. 使用int爲重點,而不是int*(見http://ideone.com/KrykZw
+0

在(hash-)集合(或有關此事的常規集合)中存儲'int *',同時允許指向對象改變並具有散列函數根據指向對象計算哈希,不僅會顯示未定義的行爲,而且在我能想到的任何實現中肯定會崩潰。您的第三個解決方案是唯一有意義的解決方案。 (請注意,即使'b'作爲const ref傳入'push','b.x'也可能會改變。) – bitmask 2013-05-13 20:03:01

+0

Thanks,2選項是我最喜歡的解決方案,因爲我不想使用複製構造函數。 – xgbuils 2013-05-13 20:15:07

+0

@jefebrondem,什麼複製構造函數? – hmjd 2013-05-13 20:29:43