You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++20移动捕获类实例报错:编译器调用已删除的拷贝构造函数

问题描述

想要为类B实现一个工厂函数,该函数需传入回调。工厂函数向B传入lambda,该lambda需要类A的实例,希望在工厂内创建A实例并移动捕获到lambda中。A不可拷贝但可移动,按预期应该可行,但编译器却尝试调用A已删除的拷贝构造函数,报错:use of deleted function 'A::A(const A&)'。

最小示例代码

#include <functional>

class A {
 public:
    A() {}

    A(const A &) = delete;
    A& operator=(const A &) = delete;

    A(A&&) noexcept {}
};

class B {
 public:
    explicit B(std::function<void()>) { };
};

B b_factory() {
    auto a { A() };
    return B {
        [a = std::move(a)]() {
            // do something with a
        }
    };
}

B b = b_factory();

编译器输出

$ arm-poky-linux-gnueabi-g++ --version
arm-poky-linux-gnueabi-g++ (GCC) 9.3.0
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

$ arm-poky-linux-gnueabi-g++ -mfpu=neon -mfloat-abi=hard -mcpu=cortex-a9 -fstack-protector-strong  -D_FORTIFY_SOURCE=2 -Wformat -Wformat-security -Werror=format-security --sysroot=/home/.../poky_sdk_toolchain/sysroots/cortexa9hf-neon-poky-linux-gnueabi --sysroot=/home/.../poky_sdk_toolchain/sysroots/cortexa9hf-neon-poky-linux-gnueabi   -I../include -O2 -pipe -g -feliminate-unused-debug-types  -g   -Wall -Wextra -Werror -Wno-psabi -std=gnu++2a -MD -MT src/lib/CMakeFiles/traplog.dir/move_example.cpp.o -MF src/lib/CMakeFiles/traplog.dir/move_example.cpp.o.d -o src/lib/CMakeFiles/traplog.dir/move_example.cpp.o -c ../src/lib/move_example.cpp
In file included from /home/.../poky_sdk_toolchain/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/9.3.0/functional:59,
                 from ../src/lib/move_example.cpp:1:
/home/.../poky_sdk_toolchain/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/9.3.0/bits/std_function.h: In instantiation of 'static void std::_Function_base::_Base_manager<_Functor>::_M_clone(std::_Any_data&, const std::_Any_data&, std::false_type) [with _Functor = b_factory()::<lambda()>; std::false_type = std::integral_constant<bool, false>]':
/home/.../poky_sdk_toolchain/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/9.3.0/bits/std_function.h:211:16:   required from 'static bool std::_Function_base::_Base_manager<_Functor>::_M_manager(std::_Any_data&, const std::_Any_data&, std::_Manager_operation) [with _Functor = b_factory()::<lambda()>]':
/home/.../poky_sdk_toolchain/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/9.3.0/bits/std_function.h:677:19:   required from 'std::function<_Res(_ArgTypes ...)>::function(_Functor) [with _Functor = b_factory()::<lambda()>; <template-parameter-2-2> = void; <template-parameter-2-3> = void; _Res = void; _ArgTypes = {}]':
../src/lib/move_example.cpp:27:5:   required from here
/home/.../poky_sdk_toolchain/sysroots/cortexa9hf-neon-poky-linux-gnueabi/usr/include/c++/9.3.0/bits/std_function.h:176:6: error: use of deleted function 'b_factory()::<lambda()>::<lambda>(const b_factory()::<lambda()>&)'
  176 |      new _Functor(*__source._M_access<const _Functor*>());
      |      ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/lib/move_example.cpp:24:26: note: 'b_factory()::<lambda()>::<lambda>(const b_factory()::<lambda()>&)' is implicitly deleted because the default definition would be ill-formed:
   24 |         [a = std::move(a)]() {
      |                          ^
../src/lib/move_example.cpp:24:26: error: use of deleted function 'A::A(const A&)'
../src/lib/move_example.cpp:8:5: note: declared here
    8 |     A(const A &) = delete;
      |     ^
问题原因与解决方案

原因分析

std::function的核心要求之一是:它存储的可调用对象必须支持拷贝构造。你的lambda通过移动捕获持有了一个不可拷贝的A实例,因此这个lambda的拷贝构造函数被编译器隐式删除(拷贝lambda需要拷贝其捕获的A,而A的拷贝构造已被删除)。当std::function<void()>的构造函数尝试拷贝这个lambda时,就会触发编译错误。

解决方案

方案1:使用智能指针持有A实例

将A的实例封装在std::shared_ptr中,让lambda拷贝捕获这个可拷贝的智能指针,从而让lambda本身支持拷贝构造:

#include <functional>
#include <memory>

class A {
 public:
    A() {}

    A(const A &) = delete;
    A& operator=(const A &) = delete;

    A(A&&) noexcept {}
};

class B {
 public:
    explicit B(std::function<void()>) { };
};

B b_factory() {
    auto a = std::make_shared<A>();
    return B {
        [a]() {
            // do something with *a
        }
    };
}

B b = b_factory();

方案2:使用C++23的std::move_only_function

如果编译器支持C++23,可以使用std::move_only_function,它专门用于存储仅可移动的可调用对象,无需支持拷贝:

#include <functional> // C++23标准中包含move_only_function

class A {
 public:
    A() {}

    A(const A &) = delete;
    A& operator=(const A &) = delete;

    A(A&&) noexcept {}
};

class B {
 public:
    explicit B(std::move_only_function<void()>) { };
};

B b_factory() {
    auto a { A() };
    return B {
        [a = std::move(a)]() {
            // do something with a
        }
    };
}

B b = b_factory();

方案3:调整B的构造函数为模板类型

如果不需要std::function的类型擦除特性,可以让B的构造函数接收模板参数,直接存储传入的lambda,避免std::function的拷贝要求:

#include <functional>
#include <utility>

class A {
 public:
    A() {}

    A(const A &) = delete;
    A& operator=(const A &) = delete;

    A(A&&) noexcept {}
};

class B {
 public:
    template<typename Func>
    explicit B(Func&& func) : func_(std::forward<Func>(func)) {}
 private:
    std::decay_t<Func> func_;
};

B b_factory() {
    auto a { A() };
    return B {
        [a = std::move(a)]() {
            // do something with a
        }
    };
}

B b = b_factory();

内容的提问来源于stack exchange,提问作者arno

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 23:24:46