- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
除了求助于 std::function
之外,还有其他方法可以存储可调用对象的同类集合吗?即,替换以下代码中的类型 T
using T = std::function<void(int)>;
std::vector<T> v{some_lambda, some_fn_ptr, some_pmf, some_functor};
还有别的吗?
当将单个可调用对象作为参数传递给高阶函数时,我尽可能使用模板来避免 std::function
的开销。但是对于收藏,我不知道有什么可以做的。
最佳答案
直接类型减少开销的最大来源是内联函数的能力。在重复应用的紧密循环中,有时可以对内联函数进行矢量化或以其他方式进行大量优化。
std::function
的第二个开销来源是它使用虚函数表。这会导致两次“随机访问”内存查找——一次针对 vtable,一次跟随 vtable 上的指针。如果这些不在先前使用的缓存中,那么它是相当昂贵的。但是,如果它们在缓存中,这最终并不昂贵(一些指令)。
std::function
的最后一个开销来源是内存分配。如果std::function
中存储的对象很大(以MSVC为例,大于sizeof(std::string)*2
,其中std::string
本身使用 SBO,因此大小适中),发生堆分配。因此,无论何时复制或创建 std::function
,都会产生相当高的成本。
这些都可以缓解。
自定义 std::function
克隆可以使用无 vtable 调用类型删除来降低 #2 的成本。这有尺寸成本。
可以编写不存储可调用对象的function_ref
类型。这些存储 void*
和 vtable
的等价物(或指向方法的直接指针)。或者,可以编写具有自定义存储大小和拒绝堆分配的 std::function
克隆。以灵 active 和/或缺乏值(value)语义为代价,可以很好地缓解#3。
第一个是最难缓解的。
如果您知道使用您的可调用对象将执行哪些操作,您可以删除到上下文中的调用,而不是删除到通用调用。
例如,假设您有一个逐像素操作。在图像的每个像素上调用 std::function
会产生大量开销。
但是,如果我们不删除每像素调用(或同样如此),而是删除每像素运行调用,我们现在可以一般地存储我们的可调用对象,并且开销从每像素变为每扫描线或每张图片!
可调用对象现在在紧密循环中可见,因此它可以被编译器内联和矢量化,并且每个扫描线仅完成一次 vtable 后续工作。
您可以变得更有趣,甚至可以使用 linestride 删除扫描线。或者有一些删除,一个用于具有零额外线跨度的扫描线,一个用于倒置扫描线,另一个用于非零线跨度,等等。扫描线长度为 2 的幂。
这些都有成本,尤其是在开发阶段。如果您已经测试并确认 std::function
确实导致了问题,那么只能沿着这条路走下去。
关于c++ - 用于收集可调用对象的 std::function 的替代方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41204607/
我正在开发一个小型图书馆,我需要做的一件事是让访问者访问一些数据并返回结果。 在一些较旧的 C++ 代码中,访问者需要声明一个 typedef return_type .例如,boost::stati
我正在尝试使用std:map类型的键和值制作std::any Visual Studio 2017 std::map m("lastname", "Ivanov"); std::cout (m["la
我已经在 C++ 的 map 中声明了一个集合为 std::map> .如何循环访问或打印设定值? 最佳答案 如果你知道如何迭代 std::map或 std::set单独地,您应该可以毫无问题地组合迭
如何循环? 我已经试过了: //----- code std::vector >::iterator it; for ( it = users.begin(); it != users.end();
我有两个用例。 A.我想同步访问两个线程的队列。 B.我想同步两个线程对队列的访问并使用条件变量,因为其中一个线程将等待另一个线程将内容存储到队列中。 对于用例 A,我看到了使用 std::lock_
我正在查看这两种类型特征的文档,但不确定有什么区别。我不是语言律师,但据我所知,它们都适用于“memcpy-able”类型。 它们可以互换使用吗? 最佳答案 不,这些术语不能互换使用。这两个术语都表示
我有以下测试代码,其中有一个参数 fS,它是 ofstream 的容器: #include #include #include #include int
这是这个问题的延续 c++ function ptr in unorderer_map, compile time error 我试图使用 std::function 而不是函数指针,并且只有当函数是
std::unordered_map str_bool_map = { {"a", true}, {"b", false}, {"c", true} }; 我们可以在此映射上使
我有以下对象 std::vector> vectorList; 然后我添加到这个使用 std::vector vec_tmp; vec_tmp.push_back(strDRG); vec_tmp.p
为什么 std::initializer_list不支持std::get<> , std::tuple_size和 std::tuple_element ?在constexpr中用得很多现在的表达式,
我有一个像这样定义的变量 auto drum = std::make_tuple ( std::make_tuple ( 0.3f , Ex
假设我有一个私有(private)std::map在我的类(class)里std::map 。我怎样才能将其转换为std::map返回给用户?我想要下面的原型(prototype) const std
假设我有一个私有(private)std::map在我的类(class)里std::map 。我怎样才能将其转换为std::map返回给用户?我想要下面的原型(prototype) const std
问题 我正在尝试将 lambda 闭包传递给 std::thread,它使用任意封闭参数调用任意封闭函数。 template std::thread timed_thread(Function&& f
我想创建一个模板类,可以容纳容器和容器的任意组合。例如,std::vector或 std::map ,例如。 我尝试了很多组合,但我必须承认模板的复杂性让我不知所措。我编译的关闭是这样的: templ
我有一个 std::vector>我将其分配给相同类型的第二个 vector 。 我收到这个编译器错误: /opt/gcc-8.2.0/include/c++/8.2.0/bits/stl_algob
有时候,我们有一个工厂可以生成一个 std::unique_ptr vector ,后来我们想在类/线程/你命名的之间共享这些指针。因此,最好改用 std::shared_ptr 。当然有一种方法可以
这个问题在这里已经有了答案: Sorting a vector of custom objects (14 个答案) 关闭 6 年前。 我创建了一个 vector vector ,我想根据我定义的参
我有三个类(class)成员: public: std::vector > getObjects(); std::vector > getObjects() const; privat
我是一名优秀的程序员,十分优秀!