2013-02-15 106 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 
     {} 
};