C++11 std::函数和std::reference包装器,用于对std::set进行排序
C++11 std::function and std::reference wrapper used for sorting std::set
我有一个C++类,它的一个字段是一组std::对象。我想编写自己的比较函数,或者让用户指定一个。在C++11中,有一种处理泛型函数类型的新方法:std::function。它适用于函数指针、成员函数指针、lambda函数等。
我试着写一个简单的实验程序,但它一直在崩溃,即使我做C++11维基百科文章建议的事情。也许我只是不明白std::function和std::ref应该如何使用。
总之,关键是当我从一个简单的lambda函数创建一个std::函数并将其作为类成员时,类的sizeof增加了22。当我从一个指向全局函数的指针创建一个std::函数时,这个std::函数的sizeof是32。所以尺寸很大。我将有许多对象使用相同的比较函数,所以我更喜欢所有对象都使用一个函数。
我有两个想法,告诉我你的想法。一个想法是,使用std::ref来存储对函数的引用,这样我就可以定义一个函数,许多对象将使用它来比较std::set元素。第二个想法:如果它不能这样工作,或者生成的函数对象太大,也许我可以使用shared_ptr。
您可能会想:为什么不拥有一个静态std::函数成员?答案是:因为所有对象都会使用相同的比较函数。例如,我希望能够拥有1000个对象,其中400个使用一个比较函数,600个使用不同的比较函数。
示例:
class MyClass
{
public:
private:
std::function<bool (int, int)> compare;
std::set<int> set;
};
现在,我如何让std::集使用std:函数,并让许多MyClass对象使用相同的函数?
我希望能够在运行时更改比较函数,这样用户就可以选择集合中对象的顺序(由GUI显示)。
表示共享所有权的标准方法是使用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
不能为null(像引用一样),因此必须使用有效的reference_wrapper
对象构造std::set
。
由于std::set
中的std::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;
}
您告诉集合在构造函数初始值设定项列表中使用比较函数:
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
{}
};
- 在声明中合并两个常量"std::set"(不是在运行时)
- 有没有办法对std::unordered_set、std::unrdered_map、std::set、std::map
- 将 std::set 与基于键的比较器一起使用
- 修改"std::set"中用户定义类型的值
- 如何在构造函数参数中初始化"std::set"?
- 如何使用 lower_bound/upper_bound 从 std::set 获取索引号?
- 如何在 C++ 中转发声明 std::set?
- 重构使用动态强制转换的 std::set 的比较运算符
- 为什么 std::set.erase(first, last) 会影响从中获取 (first, last) 的容器?
- std::set 是否将对象连续存储在内存中?
- 是否有一个 std::set 函数来确定不超过数字 x 的最大元素?
- 有什么理由不扩展 std::set 以添加下标运算符吗?
- 我从 std::set 得到const_iterator而不是迭代器
- 为什么 std:set(带有单个冒号)可以编译?
- 遍历 std::set 中包含的所有三重不同值?
- 插入 std::set 作为 std::map 的键
- 如何在 c++ 中使用默认值将 std::set 转换为 std::map
- 错误:'class std::unique_ptr<std::set<long unsigned int> >'没有名为 'size' 的成员
- 如何从 std::set 绘制 n 个元素的样本
- 为什么 std::set 容器使用的内存比其数据大小多得多?