C++ 使用std::函数移动语义

C++ 使用std::函数移动语义,c++,c++11,standards,C++,C++11,Standards,std::function提供来自右值引用的构造函数。 按标准移动的函数对象会发生什么情况?它是否为空,以便再次调用它不会产生任何影响?在20.8.11.2.1p6下,函数(函数和函数)使f处于有效状态,并带有未指定的值 empty状态是有效状态,因此您应该期望moved from函数对象可以为空 由于function执行类型擦除,并且函数对象可能会任意昂贵,因此将moved from对象保留为空的优化是有意义的: std::function<void()> g{std::bind{

std::function
提供来自右值引用的构造函数。
按标准移动的函数对象会发生什么情况?它是否为空,以便再次调用它不会产生任何影响?

在20.8.11.2.1p6下,
函数(函数和函数)
使
f
处于有效状态,并带有未指定的值

empty状态是有效状态,因此您应该期望moved from函数对象可以为空

由于
function
执行类型擦除,并且函数对象可能会任意昂贵,因此将moved from对象保留为空的优化是有意义的:

std::function<void()> g{std::bind{f, std::array<int, 1000>{}}};
std::function<void()> h{std::move{g}};
这不一定是最理想的行为;内联小可调用项(例如函数指针)会造成这样一种情况,即复制可调用项比移动它并清空已移动的from对象更有效,因此另一个实现可能会使
g
处于非空可调用状态。

[func.wrap.func.con]:

function(function&& f);
template <class A> function(allocator_arg_t, const A& a, function&& f);
函数(函数&f);
模板函数(分配器参数、常数A和A、函数和f);
效果:如果!f、 *这没有目标;否则,move会将f的目标构造为*this的目标,使f处于有效状态,并带有未指定的值

按标准移动的函数对象会发生什么情况

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

它是否为空,以便再次调用它不会产生任何影响

你不能想当然。调用函数需要它实际有一个要调用的函数。那是它状态的一部分。由于状态是未指定的,因此调用它的结果是未指定的

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

function<...> old;
function<...> new_ = std::move(old);
old = function<...>(...); //Reset to known state.
old(...); //Call is well-defined.
功能陈旧;
函数new=std::move(old);
old=函数(…)//重置为已知状态。
老(…)//呼叫定义明确。

这个问题有太多的困惑。我要把事情说清楚

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

17.6.5.15[库类型移动自]

< > C++标准库中定义的类型对象可以从 (12.8). 移动操作可以显式指定,也可以隐式指定 生成。除非另有规定,否则从物体上移动的物体应 被置于有效但未指定的状态

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

例如,您可以对从
移动的向量调用
clear()
,因为在
vector::clear()
上没有前置条件。但是你不能调用
pop_back()
,因为那是有前提条件的

具体查看
函数的调用运算符

20.8.11.2.4[功能包装功能库存]

R operator()(ArgTypes... args) const
效果:调用(f,std::forward(args)…,R)(20.8.2),其中 f是*的目标对象(20.8.1)

返回:如果R为void,则为Nothing,否则为INVOKE的返回值 (f,std::正向(args)…,R)

抛出:坏函数调用如果*这否则,将引发任何异常 通过包装的可调用对象

请注意,没有前提条件或Requires子句。这意味着调用从
函数
移动的
函数
的调用运算符不是未定义的行为。无论
函数处于何种状态,此调用都不会违反任何先决条件

请注意,在任何情况下,规范都没有说明调用将没有效果。因此,没有效果是不可能的


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

它取决于类的移动复制构造函数和/或移动赋值运算符。@juanchopanza你是什么意思?当然,这取决于move构造函数。它对原始函数对象做了什么?移动后它会是空的吗?对不起,我以为你指的是通过绑定对象传递给变量构造函数的参数。这是否也意味着被移动的函数对象可以在没有任何效果的情况下被调用?@Martin:调用它的效果是未指定或未定义的,我不太确定是哪个(即,不,你不能调用它)。函数对象的有效状态的一个例子是它包装了一个空函数指针。调用该函数会有未定义的行为。@马丁:简单地说,函数对象足够有效,可以存在,但不能使用。@Martin否。如果f在移动后为空,则表示如果您调用它,它将抛出
bad\u function\u call
。@Martin:“Unspecified”表示未指定。在C++11中,如果您在资源管理器中使用
std::function
并在析构函数中调用它,那么如果函数为空,您将得到
std::terminate()
ed,因为这就是抛出析构函数的结果。所以这只是一个小小的变化:
std::bad\u function\u call
throw,然后是
std::terminate()
@villageidiot:从什么变化
std::function
与move语义同时成为标准,析构函数(C++11)也不例外。对不起,措辞不好。我的意思是,如果在析构函数中完成,那么“仅仅”抛出就变成了对
std::terminate()
的调用。是吗?是的,除非你抓住了它,或者除非你标记了
R operator()(ArgTypes... args) const