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

标签 c++ c++11 visual-studio-2013 lambda

我有一个类 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_;
};

main 中,我构造了一个 A 的实例,在 lambda 中按值捕获它,将该 lambda 复制到 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));
}

这会打印出以下内容

A constructed
A copy constructed
A copy constructed
A destructed
A destructed
A destructed

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

最佳答案

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

编辑:感谢 Mooing Duck 在 comment on the question 中指出GCC 还将捕获存储在堆上。实际的区别似乎是 GCC 在从 lambda 构造时将捕获从 lambda 移动到 std::function

关于c++ - 将 std::function 移动到另一个 std::function 不会在捕获的变量上调用移动构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27021698/

相关文章:

C++ 析构函数返回类型

c++ - 从哪个版本的 C++ 开始允许默认参数?

xaml - 在 VS 2013 中或使用 Resharper 重新格式化 XAML

git - 在 Azure DevOps 中发布的 Git 分支未在 VS2013 或 Git 命令行中显示

c++ - 两个两个 C++ 项目可以相互引用吗?

c++ - 我应该对只有 2 个项目的列表使用迭代器吗?

c++ - 将对象的值移动到另一个但避免复制

c - 测试运行 null 和字母?

c++ - 将大字符串的逗号分隔子字符串转换为 QML 中的变体数组元素

c++ - 从类重载的新运算符运行非默认构造函数