在lambdas中移动std::shared_ptr
时我有一个奇怪的问题。我不确定它是否是一个bug,因为我可以用g ++ v6.3和clang ++ v3.9重现。
编译并运行以下程序时:
#include <iostream>
#include <memory>
void f(std::shared_ptr<int> ptr) {
std::cout << 3 << " " << ptr.get() << std::endl;
}
int main() {
auto ptr = std::make_shared<int>(42);
std::cout << 1 << " " << ptr.get() << std::endl;
#ifdef LAMBDA
auto lambda = [ptr]() {
#endif
f(std::move(ptr));
std::cout << 2 << " " << ptr.get() << std::endl;
#ifdef LAMBDA
};
lambda();
#endif
}
使用命令c++ -std=c++14 -o test main.cpp && ./test
会产生类似
的内容1 0x55a49e601c30 1
3 0x55a49e601c30 1
2 0 0
但是,将编译命令更改为c++ -std=c++14 -o test main.cpp -DLAMBDA
会使执行打印无法解释:
1 0x55a49e601c30 1
3 0x55a49e601c30 3
2 0x55a49e601c30 2
因此,似乎std::move(move)
在lambda内部执行时,实际上不会导致移动shared_ptr
,也不会阻止其引用计数器递增。
同样,我可以使用clang ++和g ++重现这一点。
这怎么可能?
答案 0 :(得分:15)
lambda中捕获的变量ptr
默认为const,即ptr
的类型为const std::shared_ptr<int>
。
std::move
无法移出const对象,因此会创建副本。
如果你真的想移动它,必须允许ptr
变为可变:
auto lambda = [ptr]() mutable {
// ^~~~~~~
答案 1 :(得分:0)
如果要在lambda中移动捕获的ptr
,则需要通过引用捕获它,如下所示:
auto lambda = [&ptr]() {
如果你想移动属于lambda的ptr
副本,你必须遵循kennytm回答。