将std :: function移动到另一个std :: function不会在捕获的变量上调用move构造函数

tcb*_*tcb 12 c++ lambda c++11 visual-studio-2013

我有一个类A在构造/复制/移动时打印出一条消息

class A
{
public:
    A(std::string s)
        :s_(s)
    {
        std::cout << "A constructed\n";
    }
    ~A()
    {
        std::cout << "A destructed\n";
    }
    A(const A& a)
        :s_(a.s_)
    {
        std::cout << "A copy constructed\n";
    }
    A(A&& a)
       :s_(std::move(a.s_))
    {
        std::cout << "A moved\n";
    }
    A& operator=(const A& a)
    {
        s_ = a.s_;
        std::cout << "A copy assigned\n";
    }
    A& operator=(A&& a)
    {
        s_ = std::move(a.s_);
        std::cout << "A move assigned\n";
    }

    std::string s_;
};
Run Code Online (Sandbox Code Playgroud)

main,我构造一个实例A,通过值捕获lambda中的lambda,将lambda复制到a中std::function,最后移动std::function到另一个std::function

int main()
{
    A a("hello ");
    std::function<void()> f = [a]{ std::cout << a.s_; };
    std::function<void()> g(std::move(f));
}
Run Code Online (Sandbox Code Playgroud)

这打印出以下内容

A constructed
A copy constructed
A copy constructed
A destructed
A destructed
A destructed
Run Code Online (Sandbox Code Playgroud)

为什么A不调用移动构造函数?f进入的最后一步不应该g调用A移动构造函数吗?

sjd*_*ing 6

复制构造函数未被精确调用,因为您已移动了std::function.这是因为std::function可以选择将捕获的值存储在堆上并保留指向它们的指针.因此,移动该函数只需要移动该内部指针.显然,MSVC选择将捕获存储在堆和GCC等上.选择将它们存储在堆栈上,因此也需要移动捕获的值.

编辑:感谢Mooing Duck在评论中指出GCC还将捕获存储在堆上的问题.实际差异似乎是GCC将捕获从lambda移动到从lambda std::function构造的时候.