带有动态存储持续时间的lambda
Lambda with dynamic storage duration
根据cppreference.com,c 11 lambda文字语法仅在直接初始化中使用。似乎没有一种直接与new
操作员直接使用lambda语法的方法。
我需要将lambda功能存储在堆中,以便可以在以后从其他线程调用它。很容易制作lambda的副本,但是是否有一种简单的方法可以直接在堆(动态存储持续时间)中分配lambda,而无需先分配堆栈(自动存储持续时间)并制作副本?
这是一个简单的示例:
#include <cstdio>
#include <cassert>
struct MyObj {
int value;
int copies;
int moves;
MyObj(int v): value(v), copies(0), moves(0) {
printf("Created object with value %d.n", value);
}
MyObj(const MyObj &other): value(other.value),
copies(other.copies+1), moves(other.moves) { }
MyObj(const MyObj &&other): value(other.value),
copies(other.copies), moves(other.moves+1) { }
};
int main (int argc, char **argv) {
MyObj o { 5 };
// Create lambda on stack (automatic storage duration)
auto f = [o] {
printf("Object value is %dn", o.value);
printf("%d copies, %d moves...n", o.copies, o.moves);
};
// Copy lambda to heap (dynamic storage duration)
decltype(f) *g = new decltype(f)(f);
// Call the copy
(*g)();
return 0;
}
上面的程序制作了2个o
的副本(一个在捕获中,另一个是将lambda复制到堆中时)。理想情况下,将只有一个副本或移动,当堆分配的Lambda捕获o
的副本时,会发生这种情况。
在C 11中,lambda表达式将以某种形式的自动对象(无论是堆栈变量还是未命名的临时性)导致某种形式的自动对象。您无能为力。
在C 17中,保证的能力使我们能够做到这一点:
new auto(<lambda>)
这使用new
分配的内存来存储该表达式的结果。这里不会创建临时的lambda对象,也不会调用lambda的任何副本/移动构造函数。最重要的是,该语言不需要lambda type 具有可以调用的复制/移动构造函数。
您需要保证省略以确保这一点。如果没有保证,那么您就可以在编译器上进行优化。标准允许此类情况填写副本。是的,任何值得使用的编译器都可能会出现此类副本。
有了保证的责任,您可以捕获固定的类型,这仍然可以在不复制任何内容的情况下起作用。pre-c 17,即使对其进行调用,您的lambda仍然需要具有副本或移动构造函数。
auto
关键字在new
表达式中是合法的,它允许您执行此操作:
// Create lambda directly in heap (dynamic storage duration)
auto g = new auto([o] {
printf("Object value is %dn", o.value);
printf("%d copies, %d moves...n", o.copies, o.moves);
});
这是整个(更新)示例:
#include <cstdio>
#include <cassert>
struct MyObj {
int value;
int copies;
int moves;
MyObj(int v): value(v), copies(0), moves(0) {
printf("Created object with value %d.n", value);
}
MyObj(const MyObj &other): value(other.value),
copies(other.copies+1), moves(other.moves) { }
MyObj(const MyObj &&other): value(other.value),
copies(other.copies), moves(other.moves+1) { }
};
int main (int argc, char **argv) {
MyObj o { 5 };
// Create lambda directly in heap (dynamic storage duration)
auto g = new auto([o] {
printf("Object value is %dn", o.value);
printf("%d copies, %d moves...n", o.copies, o.moves);
});
// Call heap lambda
(*g)();
return 0;
}
以上仅制作一份o
的副本,至少在我的平台上(Apple LLVM版本7.0.0(Clang-700.1.76))。
您可以考虑类似STD :: make_unique之类的东西:
template <typename Lambda>
std::unique_ptr<Lambda> make_unique_lambda(Lambda&& lambda)
{
return std::unique_ptr<Lambda>(
new Lambda(std::forward<Lambda>(lambda))
);
}
auto unique_lambda = make_unique_lambda([] () {
// ...
});
可以在线程上移动的多态性函数容器是一个std ::函数,可以通过lambda进行直接启动。
int main (int argc, char **argv) {
std::function<void()> g = [o = MyObj{5}]{
printf("Object value is %dn", o.value);
printf("%d copies, %d moves...n", o.copies, o.moves);
};
// Call the copy
g();
// now *move* it to another thread and call it there
std::thread t([my_g = std::move(g)] { my_g(); });
t.join();
return 0;
}
预期:
Created object with value 5.
Object value is 5
0 copies, 1 moves...
Object value is 5
0 copies, 1 moves...
- 从持续时间构造std::chrono::system_clock::time_point
- 我有一个对象,它将在整个程序的持续时间内实例化,但一个类成员不会,我应该动态分配它吗?
- 时间持续时间到时间字符串
- 指向(数据)成员的指针作为非类型模板参数,例如具有自动存储持续时间/无链接
- 为什么具有静态存储持续时间的同一内联变量在包含在 VS2017 编译的两个翻译单元中时会构造和销毁两次
- 将毫秒转换为给定格式的持续时间
- 具有静态存储持续时间的常量初始化变量的初始化顺序
- 划分和乘以STD :: Chrono ::持续时间
- 静态存储持续时间初始化
- C++计划持续时间内(字体)资源的分配
- FFMPEG:具有不同持续时间的多路复用流
- 在不同翻译单元中具有静态存储持续时间的依赖非局部常量浮点变量的常量初始化
- 使用System_Clock :: TO_TIME_T警告持续时间_t
- 访问和存储/解析性std :: Chrono ::持续时间:: milliseconds(cpprest)时使用什么类型
- 我可以让QT到概要文件插槽执行持续时间吗?
- 在STD :: Chrono ::剩余时间测量的持续时间
- 自定义 AVIOContext 的未定义 AVFormatContext 持续时间
- 使用计时比较C++的持续时间/秒数并不像预期的那样工作
- 带有动态存储持续时间的lambda
- c++ 11 lambda -为什么我需要捕获自动持续时间变量