2013-08-02 25 views
5

有多種方法可以從C++中的類的方法返回項目集合。返回集合時的權衡

例如,考慮MessageSpy類偵聽通過連接發送的所有消息。客戶可以通過多種方式訪問​​消息信息。

  1. 常量CollectionClass MessageSpy ::的getMessages()
  2. 迭代MessageSpy ::開始(),迭代器MessageSpy ::端()
  3. 空隙MessageSpy ::的getMessages(輸出迭代)
  4. 空隙MessageSpy :: eachMessage(仿函數)
  5. 其他...

每種方法都有其權衡。例如:方法1需要複製整個集合,這對於大集合來說是很昂貴的。雖然方法2使得班級看起來像一個不適合觀看的集合...

因爲我總是選擇最合適的方法,所以我不知道考慮這些方法時考慮什麼樣的折衷/成本?

+0

哎呀,這個問題的意見消失了!有一條評論與「強制性論文」的鏈接。任何人都可以再次發佈鏈接?謝謝! –

+0

@ChristianAmmer我_think_它是[這一個](http://c2.com/cgi/wiki?PrematureOptimization)。不過,圍繞相同主題的幾個「碎片」圍繞着網頁漂浮。 – sehe

回答

7

我建議在需要最輕量級解決方案的情況下使用基於迭代器/基於回調的方法。

的原因是,它由消費者從使用模式解耦供應商。 (即使結果可能「優化」 - 可能進入(N)RVO或移動而不是複製對象)仍然會爲滿容量分配一個完整的容器。

編輯:一個極好的補充「強制性文件」(他們不是;如果你想了解的東西,他們只是說非常有用):Want Speed? Pass By value由Dave亞伯拉罕。

現在

  • 這是矯枉過正,如果消費者前幾個元素

    for(auto f=myType.begin(), l=myType.end(); f!=l; ++f) 
    { 
        if (!doProcessing(*f)) 
         break; 
    } 
    
  • 後實際停止處理數據這可能是次優即使消費者最終處理al元素:可能沒有b e需要在任何特定時刻複製所有元素,因此可以重用「當前元素」的「插槽」,從而減少內存需求,從而增加緩存局部性。例如。:

    for(auto f=myType.begin(), l=myType.end(); f!=l; ++f) 
    { 
        myElementType const& slot = *f; // making the temp explicit 
        doProcessing(slot); 
    } 
    

注意Iterator接口只是尚優若消費者要包含所有元素的集合:

std::vector<myElementType> v(myType.begin(), myType.end()); 

// look: the client gets to _decide_ what container he wants! 
std::set<myElementType, myComparer> s(myType.begin(), myType.end()); 

嘗試以其他方式獲得這種靈活性。

最後,有風格的一些元素:

  • 自然很容易暴露在使用迭代器的元素(常量)的引用;這使得更容易避免對象切片,並使客戶端能夠使用多態

  • 迭代器樣式的接口可能被重載以在解引用上返回非常量引用。

    for (auto& slot : myType) 
    { 
        doProcessing(slot); 
    } 
    
:要返回的容器,如果你堅持的範圍爲基礎,在C++ 11你可以有一些語法糖的要求不能含有引用(直接)

  • 最後,(如上所示),在一般意義上,迭代器與標準庫很好地協同工作。


    回調風格(以及類似輸出迭代器風格)有很多的迭代式的(即,你可以使用返回值中止迭代中途,你可以做處理,不分配的好處預先列出所有元素的副本),但在我看來,使用起來稍微不靈活。當然,在某些情況下,您希望鼓勵某種特定的使用模式,這是一個很好的選擇。

  • 2

    第一事情(你不知何故沒有提到在所有)我想大概是

    const CollectionClass& MessageSpy::getMessages() 
    

    注意&。這返回你const引用,它不能被修改,但可以自由接受。

    沒有複製,除非你真的想複製。

    如果這不合適,例如,Qt使用"implicit data sharing"來進行大量的類。 也就是說你的類是「有點」按值返回的,但是它們的內部數據是共享的,直到你試圖對其中的一個執行寫操作。在這種情況下,您嘗試寫入的課程將執行深層複製,並且數據會停止共享。這意味着更少的數據被移動。

    有一些人對SO的返回值優化似乎太喜歡了。基本上,當你按照價值回報大的東西時,某些編譯器在某些情況下可以消除額外的副本,並立即傳遞值而繞過額外的分配,這可能比通過引用返回更快。我不會太依賴它,但如果你分析了你的代碼,並發現使用RVO提供了一個很好的加速,那麼它是值得使用的。

    我不會推薦「迭代器」,因爲在沒有auto關鍵字的C++ 03編譯器上使用它們是#& @中的皇家痛苦。長名稱或許多typedef。我會將const引用返回到容器本身。

    +0

    對於具有Qt數據共享的linq的+1 – sehe