2013-02-15 112 views
0

我有一個C++類,其中一個字段是一個std ::對象集。我想寫我自己的比較函數,或讓用戶指定一個。在C++ 11中,有一種處理通用函數類型的新方法:std :: function。它可以與函數指針,成員函數指針,lambda函數等一起工作。C++ 11 std ::函數和std ::引用包裝用於排序std :: set

我試着編寫一個簡單的實驗程序,但它始終如一地工作,即使我做C++ 11維基百科文章的建議。也許我只是不明白如何使用std :: function和std :: ref。

無論如何,關鍵是當我從一個簡單的lambda函數創建一個std ::函數並將其作爲一個類成員時,該類的sizeof增加了22.當我從一個指針創建一個std :: function到一個全局函數,這個std :: function的sizeof是32.所以它的大小很大。我將使用相同的比較函數有很多對象,所以我更喜歡使用它們中的一個函數。

我有兩個想法,告訴我你的想法。一個想法是,使用std :: ref存儲對函數的引用,這樣我可以定義一個函數,許多對象將使用它來比較std :: set元素。第二個想法:如果它不能這樣工作,或者由此產生的函數對象太大,也許我可以使用shared_ptr。

你可能會問:爲什麼不能有一個靜態的std :: function成員?答案是:因爲那麼所有對象都將使用相同的比較函數。我希望能夠擁有1000個對象,其中400個使用一個比較函數,600個使用不同的比較函數。

例子:

class MyClass 
{ 
public: 
private: 
    std::function<bool (int, int)> compare; 
    std::set<int> set; 
}; 

現在我該怎樣做的std ::設置使用std ::功能,並有許多MyClass的對象使用相同的功能?

我希望能夠在運行時更改比較函數,以便用戶能夠選擇集合中的對象(通過GUI顯示)的排序。

+3

相反的描述你做什麼或想以文字做的,爲什麼不能讓一個[ SSCCE](http://sscce.org/)並向我們展示實際的代碼? – 2013-02-15 11:00:01

+0

因爲我從來沒有聽說過任何叫做SSCCE的東西,因爲我沒有實際的代碼;我發佈了這個問題,因爲我正在尋找如何正確編寫它的指導。 (我得到了指導,看到下面的答案) – cfa45ca55111016ee9269f0a52e771 2013-02-15 12:45:58

回答

2

表示共享所有權的標準方式是使用std::shared_ptr。這會增加更多的開銷,迫使你在堆上分配std::function,但shared_ptr小於std::function,它會正確地管理它的生命週期,所以當任何對象仍在使用該函數對象時,它將保持活動並且將自動地在不再需要時被銷燬。

如你建議,一個reference_wrapper參照共享功能可以被用作set的比較對象,是因爲一個reference_wrapper是可調用如果它包裝一個可調用的類型。

class MyClass 
{ 
    typedef std::function<bool (int, int)> func_type; 
public: 
    MyClass(std::shared_ptr<func_type> const& f) 
    : compare(f), set(std::ref(*f)) 
    { } 
private: 
    std::shared_ptr<func_type> compare; 
    std::set<int, std::reference_wrapper<func_type>> set; 
}; 

一個reference_wrapper不能爲空(如引用),所以你必須有一個有效的reference_wrapper對象構造std::set

由於在std::setstd::reference_wrapper只是持有非所屬指針std::function,你需要小心在同一時間更新設定的比較對象作爲更新shared_ptr,或者你可以刪除最後一個參考函數,所以shared_ptr會破壞它,在集合中留下一個懸掛指針。可以做這樣的:

void MyClass::replace_cmp(std::shared_ptr<func_type> const& f) 
{ 
    set = std::set<int, std::reference_wrapper<func_type>>(std::ref(*f)); 
    compare = f; 
} 
+0

但現在,我該如何將它傳遞給std :: set?該集合需要一個可調用的類型,所以我需要用一個調用「compare」的operator()編寫一個類。對?或者有更短的路? – cfa45ca55111016ee9269f0a52e771 2013-02-15 11:30:59

+0

對不起,我錯過了那一點:)答案更新 - 一個'reference_wrapper'提供'operator()' – 2013-02-15 11:40:12

+0

因此,reference_wrapper只是調用它存儲的shared_ptr指向的std ::函數?還有一個關於性能的問題:如果std :: set使用operator()接受一個對象,並使用默認的ctor構造一個對象,它通常會很聰明並嘗試內聯該函數? (因爲在這種情況下它在編譯時已知)在我的情況下函數是未知的,所以我失去了這個機會 – cfa45ca55111016ee9269f0a52e771 2013-02-15 11:48:33

2

你告訴設置爲使用比較功能在您constructor initializer list

class MyClass 
{ 
public: 
    template<typename Fc> 
    MyClass(Fc compare_func) 
     : compare(compare_func), // Initialize the comparison function 
      set(compare)   // Tell the set to use out function for comparison 
     {} 
};