Search code examples
c++11lambdac++14shared-ptrmove

std::move with std::shared_ptr in lambda


I have a strange issue when moving std::shared_ptrs in lambdas. I am not sure if it is a bug or not, as I can reproduce with g++ v6.3 and clang++ v3.9.

When I compile and run the following program:

#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
}

with the command c++ -std=c++14 -o test main.cpp && ./test yields something like

1 0x55a49e601c30 1
3 0x55a49e601c30 1
2 0 0

However, changing the compilation command to c++ -std=c++14 -o test main.cpp -DLAMBDA makes the execution print something I cannot explain:

1 0x55a49e601c30 1
3 0x55a49e601c30 3
2 0x55a49e601c30 2

So, it appears that the std::move(move), when performed inside a lambda, does not actually cause the shared_ptr to be moved, nor does it prevent its reference counter to be incremented.

Again, I can reproduce this with clang++ and g++.

How is that possible?


Solution

  • The captured variable ptr in a lambda is by default const, i.e. the type of ptr is const std::shared_ptr<int>.

    std::move cannot move out const objects, so a copy is created instead.

    If you really want to move it, the ptr must be allowed to be mutable:

    auto lambda = [ptr]() mutable {
    //                    ^~~~~~~