2016-05-04 63 views
0

給定一個unordered_map對象,想知道是否有可能通過節點的引用(或地址)擦除節點。換句話說,在下面的代碼片段中,想知道是否可以通過變量x的地址或類似的東西來刪除「UK」的節點。根據節點的地址刪除unordered_map中的節點

std::unordered_map<std::string,int> mymap; 

// populating container: 
mymap["US"] = 10; 
mymap["UK"] = 9; 
mymap["US"] ++; 
mymap["France"] = 8; 
int &x = mymap["UK"]; 

這是有用的在應用,在那裏我需要跟蹤各個串的頻率在時間間隔(比如說,在最後3小時)。字符串的大小可以從幾個字節到幾千個字節。每當一個字符串到期(根據它的到達時間和時間間隔的大小),我會減少這個字符串的頻率。如果頻率爲0,則需要刪除該字符串的節點。不想分配空間來將字符串存儲在定時器隊列中,這會浪費空間。

任何想法?謝謝。

+0

你可以存儲的shared_ptr 對象,而不是簡單的字符串,這樣你可以在相同的字符串存儲在unordered_map和定時器隊列兩者,仍然會有各只有一個字符串拷貝到內存中。 –

回答

0

不能從本身的價值做到這一點,但你可以使用std::map::find得到一個迭代有趣的項目在地圖上直接刪除重複值的鍵/值對。通過迭代

  • 通過鍵

沒有這樣 「通過的映射值地址擦除」:

2

unordered_map支持兩種erase重載。基本上你做這件事的方法有兩種:

int main() { 
    unordered_map<string, int> data; 

    data["UK"] = 10; 
    data["UK"]++; 
    data["US"] = 8; 

    cout << data.size() << endl; 
    auto it = data.find("UK"); 
    data.erase(it); 
    cout << data.size() << endl; 
    data.erase("US"); 
    cout << data.size() << endl; 
    return 0; 
} 

使用迭代器比較有效,因爲你可以得到(通過second成員)的值,並一起刪除它,而不需要做兩個查找。

通過您的評論,你不能把一個迭代器的地址通過一個局部變量的值獲得。這將在任何情況下產生的本地地址,但標準保證您在unordered_map迭代器沒有插入時失效和刪除只有受影響的一個無效,所以將它們存儲的地方是允許的,是這樣的:

#include <iostream> 
#include <vector> 
#include <unordered_map> 

using namespace std; 
using map_type = unordered_map<string, int>; 

map_type data; 
vector<map_type::iterator> timer_queue; 

void timeTick() 
{ 
    for_each(begin(timer_queue), end(timer_queue), [](map_type::iterator& it) { 
    --it->second; 

    if (it->second == 0) 
    { 
     cout << "pair " << it->first << " has expired" << endl; 
     data.erase(it); 
     cout << "map size: " << data.size() << endl; 
    } 
    }); 
} 

template<typename... Args> void addElement(Args... args) 
{ 
    auto it = get<0>(data.emplace(args...)); 
    timer_queue.push_back(it); 
} 

int main() { 

    addElement("IT", 5); 
    addElement("US", 10); 
    addElement("UK", 8); 

    while (!data.empty()) 
    { 
    cout << "time tick" << endl; 
    timeTick(); 
    } 

    return 0; 
} 
+0

感謝您的代碼片段。我需要保留一個定時器隊列,對於每個定時器,我需要有一些信息來定位節點在地圖中。我可以使用字符串,但這太浪費了,這就是爲什麼我認爲我可能會保留節點的地址。我需要在結構的8字節字段中轉換迭代器,所以我需要以下轉換:'std :: unordered_map :: const_iterator it = mymap。找到( 「UK」); \t void * x =(void *)it;',但編譯失敗。任何想法如何做到這一點?謝謝。 – packetie

+0

@codingFun:檢查我的編輯 – Jack

0

我不會推薦用於生產代碼,但是如果您可以假設您的STL的unordered_map實現將鍵和值一起存儲在結構中,並且因此將鍵和值的存儲位置如果給定的鍵/值對總是處於固定的偏移位置,則可以使用下面的GetKeyFromValue()函數來檢索與您的引用值關聯的鍵。然後,您可以像往常一樣使用該密鑰來擦除()或其他任何內容。

#include <iostream> 
#include <string> 
#include <unordered_map> 

using namespace std; 

/** Given a reference to a value in (map), returns a reference to the associated key. 
    * @param map Reference to the unordered_map object. 
    * @param value Reference to a value in (map). If this reference is to some object that is 
    *    not actually stored in (map), then this function's behavior is undefined, so be careful! 
    * @returns A reference to the key associated with (value). 
    */ 
template<typename KeyType, typename ValueType> const KeyType & GetKeyFromValue(const unordered_map<KeyType, ValueType> & map, const ValueType & value) 
{ 
    if (map.size() == 0) throw invalid_argument("Called GetKeyFromValue() on an empty map!?"); 

    auto it = map.begin(); 
    const KeyType * firstKey = &it->first; 
    const ValueType * firstVal = &it->second; 

    const char * cFirstKey = reinterpret_cast<const char *>(firstKey); 
    const char * cFirstVal = reinterpret_cast<const char *>(firstVal); 
    ptrdiff_t diff = cFirstVal-cFirstKey; 

    const char * cUserVal = reinterpret_cast<const char *>(&value); 
    cUserVal -= diff; 
    return *(reinterpret_cast<const KeyType *>(cUserVal)); 
} 

// Quick unit test for the above 
int main(int, char **) 
{ 
    unordered_map<string, int> mymap; 
    mymap["US"] = 10; 
    mymap["UK"] = 9; 
    mymap["US"]++; 
    mymap["France"]=8; 

    int & x = mymap["UK"]; 
    const string & uk = GetKeyFromValue(mymap, x); 
    cout << "keyForX=[" << uk << "]" << endl; 

    int & y = mymap["France"]; 
    const string & france = GetKeyFromValue(mymap, y); 
    cout << "keyForY=[" << france << "]" << endl; 

    return 0; 
} 
+0

感謝@ jeremy-friesner的示例代碼,這真是一個很大的假設!我正在考慮存儲迭代器(8字節)。 – packetie

+0

請注意,只要unordered_map被修改,迭代器就會失效;不知道這是否會成爲你的問題。 (然後,當unordered_map被修改時,持有的引用值可能會失效) –

+0

感謝您指出,您是對的,對迭代器的引用可能無效。似乎很難想出一個(記憶方式)最佳解決方案來跟蹤時間間隔內字符串的頻率。 – packetie