在执行std::函数对象时重新分配该对象
Re-assigning an std::function object while inside its execution
我有一个std::function对象,我正在使用它作为某个事件的回调。我将一个lambda分配给这个对象,在这个对象中,我在执行过程中将该对象分配给不同的lambda。当我做这件事的时候,我会犯一个错误。这不是允许我做的事情吗?如果是,为什么?我将如何实现这一目标?
声明:
std::function<void(Data *)> doCallback;
调用:
//
// This gets called after a sendDataRequest call returns with data
//
void onIncomingData(Data *data)
{
if ( doCallback )
{
doCallback(data);
}
}
任务:
doCallback =
[=](Data *data)
{
//
// Change the callback within itself because we want to do
// something else after getting one request
//
doCallback =
[=](Data *data2)
{
... do some work ...
};
sendDataRequest();
};
sendDataRequest();
标准没有指定函数在std::function::operator()
的操作中何时使用其内部状态对象。在实践中,一些实现在调用之后使用它。
所以你所做的是未定义的行为,尤其是崩溃。
struct bob {
std::function<void()> task;
std::function<void()> next_task;
void operator()(){
next_task=task;
task();
task=std::move(next_task);
}
}
现在,如果您想更改下一次在bob()
中调用bob
时发生的情况,只需设置next_task
即可。
简短回答
这取决于(重新)赋值后,被调用的lambda是否访问其任何非静态数据成员。如果是这样,则会得到未定义的行为。否则,我相信不会有什么不好的事情发生。
长答案
在OP的示例中,调用由std::function
对象持有的lambda对象(此处用l_1
表示),并且在执行过程中,std::function
对象被分配给另一个lambda对象,此处用l_2
表示。
分配调用template<class F> function& operator=(F&& f);
,到20.8.11.2.1/18,CCD_9具有的效果
function(std::forward<F>(f)).swap(*this);
其中f
绑定到l_2
,*this
是被分配到的std::function
对象。此时,临时std::function
保存l_2
,*this
保存l_1
。在CCD_ 18之后,临时保持CCD_ 19并且CCD_。然后临时性被破坏,l_1
也被破坏。
总之,在l_1
上运行operator()
时,此对象会被销毁。然后根据12.7/1
对于具有非平凡构造函数的对象,在构造函数开始执行之前引用该对象的任何非静态成员或基类会导致未定义的行为对于具有非平凡析构函数的对象,在析构函数完成执行后引用该对象的任何非静态成员或基类会导致未定义的行为
Lambdas非静态数据成员对应其捕获。所以,如果你不访问它们,那应该没问题。
亚克的回答提出了一个更重要的观点。据我所知,问题是std::function::operator()
在将呼叫转发给l_1
后,是否试图访问l_1
(现在已经失效)?我不认为是这样,因为std::function::operator()
的影响并不意味着这一点。事实上,20.8.11.2.4说,这次通话的效果是
INVOKE(f, std::forward<ArgTypes>(args)..., R)
(20.8.2),其中f
是*this
的目标对象(20.8.1)。
基本上说CCD_ 32调用CCD_。
(*)我正在详细说明交换是如何发生的,但这个想法仍然有效。(例如,如果临时保存l_1
的副本而不是指向它的指针,该怎么办?)
- 有没有一种方法可以使用placement new将堆叠对象分配给分配的内存
- C++ 如何在将新对象分配给另一个对象时创建新对象
- 为什么我可以在不重载 "=" 运算符的情况下将一个对象分配给另一个对象?
- 为对象分配整数.输出将是什么?
- C++ 使用枚举类对象分配 std::map 值
- 如何在C++中为增加但记住删除先前对象的对象分配唯一标识符
- 我重载了 << 和 = 运算符。为什么当我将一个对象分配给另一个对象并尝试打印它时,我会被打印出来?
- 为什么将两个对象分配给另一个对象后,两个对象不一样?
- 有没有办法在同名类 (c++) 中为对象分配一个指针变量
- 如何使用函数(而不是构造函数)将派生类对象分配给基类指针
- 是否可以使用 malloc 为类对象分配内存?
- 将对象分配给数组C++
- 我们可以在cpp中为对象分配函数吗
- 为模板参数类型中的新对象分配内存
- 我无法将对象分配给对象数组
- 对象分配-成员函数的使用无效错误
- 将派生对象分配给函数内的基类指针
- Arduino ESP32如何将BLEUUID对象分配到字符串中
- Rapidjson将密钥值从一个文档对象分配到另一个文档对象
- 奇怪的对象分配行为C