2014-02-17 65 views
1

我試圖通過將字符串爲unordered_set<string>,然後繞過shared_ptr<string>的以削減字符串複製(已測得爲我的應用程序中的性能瓶頸)。很難知道集合中所有對字符串的引用何時被刪除,所以我希望shared_ptr可以幫助我。這是未經測試的代碼,說明我是多麼希望能夠把它寫:使用一個shared_ptr <string>到unordered_set <string>

unordered_set<string> string_pool; 
: 
shared_ptr<string> a = &(*string_pool.emplace("foo").first); // .first is an iterator 
: 
shared_ptr<string> b = &(*string_pool.emplace("foo").first); 

在字符串「foo」應在string_pool上面,只有一個實例; a和b都應該指向它;並且在a和b都被破壞的時候,應該從string_pool中刪除「foo」。

暗示,但是對我來說並不明顯,那個指針a可以在指針b的分配引起的重新散亂中生存下來。它也似乎保證了「foo」的第二次放置不會導致任何重新分配,因爲它被認爲已經存在於集合中。

我在正確的軌道上嗎?我需要保持string_pool不斷增長,但是我沒有任何一點可以簡單地清除它,也沒有任何明確的字符串「擁有者」。

更新1

這個問題的歷史:這是一個「交通警察」的應用程序,從服務器,包裹出的數據讀入到其他服務器,接受他們的答案,包裹那些給他人,接收,最後彙編並返回一個簡要答案。它包括一個應用協議棧,它接收TCP消息,將它們解析爲字符串標量值,然後應用程序將其組裝成其他TCP消息,發送,接收等。我最初使用string s,vectors<string> s和字符串引用來編寫它,並且valgrind報告了「高數量」的字符串構造函數(即使使用-O3進行編譯),以及與字符串相關的庫例程中重點關注的高CPU使用率。我被要求調查減少字符串複製的方法,並設計了一個「memref」類(char *和指向輸入緩衝區的長度),可以複製這些類型來代替字符串本身。然後出現這種情況,需要重新使用輸入緩衝區,而memrefs仍然需要有效,所以我付了代價將每個緩衝區的子字符串複製到一個內部區域(unordered_set<string>)中,並將memref指向那裏。然後我發現在這個過程中找到一個地方是很困難和不方便的,因爲在這個過程中,可以一次清理拘留區域(爲了防止它不受限制地增長),我開始嘗試重新設計拘留區域,以便當所有的遊覽區域interned字符串不見了,字符串將從池中刪除。因此shared_ptr。

正如我在@Peter R的評論中提到的那樣,我對移動語義和容器以及引用的瞭解比現在更不自在,而且很可能我沒有編寫簡單的,基於字符串的解決方案來使用所有C++ 11都可以提供。到現在爲止,我似乎一直在大循環旅行。

回答

1

unordered_set擁有字符串。當它超出範圍時,你的字符串將被釋放。 我的第一印象是,您的方法聽起來不像在可維護性或可測試性方面會帶來積極的體驗。當然這

shared_ptr<string> a = &(*string_pool.emplace("foo").first); 

是錯誤的。您已在unordered_set中擁有該字符串的所有者。試圖用shared_ptr將其他所有權層放在它上面是行不通的。你可以有一個unordered_set<shared_ptr<string>>,但即使這我不會推薦。

如果不理解其他代碼庫,很難在此推薦'解決方案'。移動語義和傳遞const string&的組合應該處理大多數低級別的需求。如果仍然存在性能問題,那麼他們可能會成爲架構。當然,如果沒有字符串的自然擁有者,只使用shared_ptr<string>可以解決您的終生問題,並且它們很便宜,但在這種情況下不要使用unordered_set<string>

+0

較大規模的ç unordered_set永遠不會超出範圍。我想它的主要貢獻是隻保留每個字符串值的單個實例。然而,更重要的是,當我最初編寫我一直試圖優化的代碼時,我比現在更瞭解移動語義和引用,而且我懷疑我寫的代碼效率低下。我會向OQ追加一個更好的解釋,我想要做什麼。 – Chap

+0

稱爲「塊」的對象具有輸入緩衝區,其中讀取了製表符分隔的字符串。 Block的緩衝區解析器創建一個'std :: strings'的vector。用戶調用Block訪問器方法來獲取這些字符串。一旦它們在用戶的手中,它們的生命週期是不可預知的,並且它們肯定會超過輸入緩衝區和字符串向量。你是否同意這樣的字符串沒有「自然的所有者」? – Chap

1

你已經有點兒任性了。 shared_ptr在概念上構成了一組對象的共享所有者......第一個shared_ptr應該使用make_shared創建,然後在複製該值時自動創建其他副本(帶有「值」語義)。什麼你試圖進入那個是有缺陷的:

  • string_pool本身存儲string s表示不會在共享所有權參加,也沒有在其中string_pool通知或更新任何時候的shared_ptr引用計數擊中0

  • share_ptr■找對方沒有任何關係(你給他們兩個原始指針,而不是複製一個令對方)

爲了您的使用,您需要決定是否在某個時間點主動erase來自string_pool的字符串,否則您可能需要將weak_ptr放入string_pool並檢查共享string實際上是否仍然存在使用它。如果你不熟悉這個概念,你可以谷歌weak_ptr。


另外,值得一檢查字符串拷貝是否當前的觀察是一個性能問題是由於低效率的編碼。例如:

  • 是你string變量引用傳來傳去哪裏可能的,例如:const std::string&函數的參數時,你將不會改變他們

  • 你用static const string做得相當比連續運行時間娛樂從字符串文字/字符數組?

  • 你與優化的合理水平(例如-02,/ O2)

  • 有沒有地方編制,其中一個保持字符串中參照string和偏移量將大規模提高性能和降低內存使用情況(所引用的字符串必須只要它甚至間接用於保持周圍) - 這是很常見的實現「string_ref」或類似的類,這是中期和++項目

+0

作爲事實上,這是* *是指到輸入緩衝區的「memref」。後來我發現情況時使用所需的緩衝液的第二時間,同時memrefs到仍然需要第一緩衝器是有效的,所以我「實習」每個子作爲一個單獨的字符串中的'unordered_set '第一,然後指出了memref那裏。我認爲總會有一個用戶可以調用一個函數來清除實例集的點,但這並非易事。所以我決定試試當不再被引用時會消失的字符串。 – Chap

+0

(見一個更全面的解釋原來的問題的更新1) – Chap

+0

感謝澄清如何使用shared_ptr的。這聽起來像我最大的缺陷是在想,去除最終參考的字符串可以以某種方式導致字符串從unordered_set被刪除。 – Chap

相關問題