Dan*_*olf 12 c++ lambda raii c++11
假设我有两个本地智能指针,foo并且bar.
shared_ptr<Foo> foo = ...
shared_ptr<Bar> bar = ...
Run Code Online (Sandbox Code Playgroud)
这些智能指针是围绕资源的包装器,由于某种原因必须按顺序销毁foo,然后bar.
现在我想创建一个使用foo和的lambda bar,但是比包含它们的范围更长.所以我会按价值捕捉它们,如下所示:
auto lambda = [foo, bar]() { ... };
Run Code Online (Sandbox Code Playgroud)
这将在函数对象中创建foo和复制bar.当函数对象被破坏时,这些副本也将被破坏,但我关心这种情况发生的顺序.所以我的问题是:
当一个lambda对象被破坏时,它的by-value会以什么顺序捕获被破坏的?我怎么能(希望)影响这个命令呢?
Nic*_*las 15
该规范涵盖了这种...... 从5.1.2第14段开始:
如果隐式捕获实体并且捕获默认值为=,或者使用不包含&的捕获显式捕获实体,则通过副本捕获实体.对于由副本捕获的每个实体,在闭包类型中声明未命名的非静态数据成员.这些成员的声明顺序未指定.
强调补充说.由于未指定声明顺序,因此未指定构造顺序(因为构造顺序与声明顺序相同).因此,破坏顺序是未指定的,因为破坏的顺序与构造顺序相反.
简而言之,如果您需要关注声明顺序(以及关键的各种构造/销毁订单),则不能使用lambda.你需要制作自己的类型.
你应该解决这个问题,而不是担心破坏的顺序.注意到您正在为两个对象使用共享指针,您可以通过在对象中添加共享指针来确保破坏的顺序,这需要比另一个更长.在这一点上是否foo或bar更早破坏并不重要.如果顺序正确,破坏共享指针将立即释放对象.如果顺序不正确,则附加共享指针将使对象保持活动状态,直到另一个消失为止.
正如尼科尔所说,破坏的顺序没有具体说明.
但是,你不应该依赖于lambda的破坏.您应该能够简单地foo在lambda的末尾重置,从而确保它在之前释放它的资源bar.你还必须标记lambda mutable.这里唯一的缺点是你不能多次调用lambda并期望它能够工作.
auto lambda = [foo, bar]() mutable { ...; foo.reset(); };
Run Code Online (Sandbox Code Playgroud)
如果你确实需要多次调用lambda,那么你需要提出一些其他方法来控制释放的顺序.一种选择是使用具有已知数据成员顺序的中间结构,例如std::pair<>:
auto p = std::make_pair(bar, foo);
auto lambda = [p]() { auto foo = p.second, bar = p.first; ... };
Run Code Online (Sandbox Code Playgroud)
根据我拥有的 C++11 文档(即免费赠品,稍早于批准的 n3242),第 5.1.2 节第 21 段,捕获按声明顺序构造,并按相反的声明顺序销毁。然而,声明顺序未明确(第 14 段)。所以答案是,“以未指定的顺序”和“你不能影响它”(我想除了通过编写编译器)。
如果 bar 确实需要在 foo 之前被破坏,那么 bar 持有一个指向 foo 的共享指针(或类似的东西)是明智的。