我应该何时存储函数的引用或指针?

时间:2018-01-23 18:10:37

标签: c++ c++11 std-function

我有一个std :: functions

的向量
Using Functors = std::vector<std::function<bool(int)>>;
Functors fs;

现在,如果我想向向量添加一个函数,我会这样做:

fs.emplace_back(
    [](int v)->bool { return v > 1; }
)

我想知道当我声明“Functors”时,我应该指向std :: function而不是raw std :: function吗?这意味着,我将这样声明:

    Using Functors = std::vector<
     std::function<bool(int)>*
    >; // note the last &

因此,当我调用emplace_back时,我只会传入指针而不是复制?或者lambda闭合可以移动?请在这里说明一下:我何时应该使用std :: function?

的引用

3 个答案:

答案 0 :(得分:7)

只需使用std::vector<std::function<bool(int)>>

移动时

std::function几乎总是便宜。

为了不便宜,存储的函数对象必须(A)小,(B)有一个no-except移动构造函数,(C)移动成本很高。

有意识地这样的对象并不困难,但很难不小心写一个

现在,标准没有规定多小;对于MSVC,他们将其设置为一个或两个std::string的大小,作为示例。

管理原始指针的开销几乎肯定会使你的代码比使用这里的值更差,性能更差。两者都是因为你正在燃烧精神资源来修复原始指针错误,并且因为在免费商店中分配对象比std::function几乎任何类型移动几个数量级时都要贵。

平均而言,std::vector中的元素将被移动恒定次数(通常为1-3),如果您使用push_back填充空白的向量,因为内存管理的强制增长指数地,只有在需要调整大小时才会移动对象。

拥抱价值语义。

答案 1 :(得分:1)

首先,引用不能是模板的参数类型,因此您需要使用指针或std::reference_wrapper代替:

std::vector<std::function<bool(int)>*>
std::vector<std::reference_wrapper<std::function<bool(int)>>>

在您的示例中,您的向量将无法保存对函数的“引用”,因为您在r值上调用emplace_back。所以在这里,std::vector<std::function<bool(int)>>似乎是一个很好的解决方案。

答案 2 :(得分:1)

简而言之:从不! (至少在你谈论std::function<...>*时没有 - 见下文)

如果你真的只想存储函数,请创建一个函数指针向量:

std::vector<bool(*)(int)> fs;

这也适用于示例中带有空捕获的lambdas,因为它们隐式转换为函数指针。

如果你想存储任意能力的对象,{99}的时间std::vector<std::function<bool(int)>>;应该没问题。这很简单,你不太可能犯任何错误和最节省空间的解决方案。

如果你真的想出于某种原因在堆上创建std :: function对象,那么使用unique_ptr:

std::vector<std::unique_ptr< std::function<bool(int)> >> fs;
fs.push_back( std::make_unique< std::function<bool(int)> >( [](int){ return true;}) );

这将确保您不会忘记删除这些对象。

<强>解释

也许我错了,但在我看来好像你对std::function是什么有误解。它不是表示本机函数的类,而是一个(相当繁重的)类,它可以包装任何可调用的函数(函数,函数对象,指向成员函数的指针 - 甚至指向成员的指针)。

  • 存储函数指针非常有效(它们只有4-8个字节大而且可以复制/移动)并且安全,因为函数的地址在整个程序中都是有效的(忽略动态加载共享库)。
  • 通过std::function的间接增加了显着的开销(它们通常是大小的指针,移动/复制是实际的功能),但它仍然是安全的。
  • 将原始指针存储到std::function通常需要在堆上创建该对象,这需要额外的开销,但至少移动再次便宜。然而,它伴随着原始拥有指针的通常问题。因此,std::unique_ptr的解决方案。