使用std :: function移动语义

时间:2012-12-03 09:43:41

标签: c++ c++11 standards

std::function提供了rvalue引用的构造函数。 按标准移动的函数对象会发生什么?它是否为空,以便再次调用它没有效果?

4 个答案:

答案 0 :(得分:19)

围绕这个问题存在太多混淆。我打算试着清楚地说清楚......

本节介绍std定义对象的移动状态:

17.6.5.15 [lib.types.movedfrom]

  

可以移动C ++标准库中定义的类型的对象   (12.8)。可以明确指定或隐式指定移动操作   产生。除非另有规定,否则此类移动物体应   被置于有效但未指明的状态。

这是什么意思?这意味着给定一个std定义的移动对象,您可以对该对象执行任何操作,而该对象不需要该对象状态的先验知识。不需要事先了解当前状态的行动类别是那些没有先决条件的行为。

例如,您可以在移动clear()上致电vector因为vector::clear()没有先决条件。但你不能打电话给pop_back(),因为那确实有先决条件。

特别关注function的调用运算符:

20.8.11.2.4 [func.wrap.func.inv]

R operator()(ArgTypes... args) const
  

效果:INVOKE(f,std :: forward(args)...,R)(20.8.2),其中   f是* this的目标对象(20.8.1)。

     

返回:如果R为空则无效,否则为INVOKE的返回值   (f,std :: forward(args)...,R)。

     

抛出:bad_function_call if!* this;否则,抛出任何异常   由包装的可调用对象。

请注意,没有前置条件或Requires子句。这意味着调用移动function的{​​{1}}的调用操作符不是未定义的行为。无论function处于什么状态,您都不会违反此次通话的任何先决条件。

请注意,规范在任何情况下都不会说该调用无效。所以没有效果是不可能的。

调用将调用包装函数,或者抛出function。这是唯一的两个选择。它的行为取决于bad_function_call对象的状态。并且function对象的状态未指定([lib.types.movedfrom])。

答案 1 :(得分:13)

在20.8.11.2.1p6下,function(function &&f) f置于具有未指定值的有效状态

空状态是一个有效状态,因此您应该期望从函数对象移动可以为空。

因为function执行类型擦除,并且函数对象可以任意昂贵,所以将从对象移动的优化是有意义的:

std::function<void()> g{std::bind{f, std::array<int, 1000>{}}};
std::function<void()> h{std::move{g}};

通过从h移动来构建g后,可以预期包含的bind已从g转移到h而不是复制,所以g将被留空。

对于以下程序,gcc 4.5.1打印empty

#include <functional>
#include <iostream>
void f() {}
int main() {
    std::function<void()> g{f}, h{std::move(g)};
    std::cout << (g ? "not empty\n" : "empty\n");
}

这不一定是最理想的行为;内联小型callables(例如函数指针)会产生一种情况,即复制callable比移动它并清空移动的对象更有效,因此另一个实现可能会使g处于非空的可调用状态。

答案 2 :(得分:6)

  

标准移动的函数对象会发生什么?

它将处于有效状态(因此可以使用该对象),但它所处的实际状态是未指定的。最后一部分意味着调用任何需要该对象处于特定状态的函数不一定有效。

  

它是否为空,以便再次调用它没有效果?

不能假设它会。调用该函数需要它实际上具有调用函数。这是该州的一部分。由于状态未指定,因此调用它的结果未指定。

如果您想以某种有意义的方式再次使用该对象,只需创建一个新的function并将其分配给它:

function<...> old;
function<...> new_ = std::move(old);
old = function<...>(...); //Reset to known state.
old(...); //Call is well-defined.

答案 3 :(得分:0)

[func.wrap.func.con]:

function(function&& f);
template <class A> function(allocator_arg_t, const A& a, function&& f);
  

效果:如果!f,*这没有目标;否则,移动 - 将f的目标构造到* this的目标中,使f处于具有未指定值的有效状态。