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

添加析构函数后vector::emplace_back触发编译错误的原因排查

为何给MyClass2添加自定义析构函数后,emplace_back触发"result type must be constructible from input type"编译错误

问题本质

当你给MyClass2添加自定义析构函数时,编译器会按照C++规则自动禁用默认移动构造函数和默认拷贝构造函数的生成。而std::vector在扩容时(比如初始容量不足,需要重新分配内存),必须能够移动或拷贝已有元素到新内存区域,此时因为MyClass2没有可用的移动/拷贝构造逻辑,就触发了静态断言错误。

具体原因拆解

  • 没有自定义析构函数时,C++编译器会自动生成默认移动构造函数,std::unique_ptr支持移动操作,所以vector扩容时可以通过移动构造转移元素,不会报错。
  • 一旦添加了自定义析构函数,编译器就不再自动生成移动构造/赋值、拷贝构造/赋值。而MyClass2中的std::unique_ptr是不可拷贝的,默认拷贝构造函数会被自动删除,此时MyClass2既不能被移动也不能被拷贝,vector扩容时无法处理元素迁移,就会抛出这个静态断言错误。

解决方案

你可以根据需求选择以下任一方案:

方案1:添加移动构造函数(推荐,符合unique_ptr的语义)

给MyClass2显式定义移动构造函数,让vector可以通过移动操作完成扩容:

struct MyClass2
{
    std::unique_ptr<MyClass> my;

    MyClass2(const MyClass& my2)
    {
        my.reset(new MyClass(my2.x));
    }
    
    ~MyClass2()
    {
        printf("deleting\n");
    }

    // 添加移动构造函数
    MyClass2(MyClass2&& other) noexcept : my(std::move(other.my)) {}
};

方案2:提前预留vector容量,避免扩容

如果确定要插入的元素数量,可以提前调用reserve预留足够空间,这样vector不需要扩容,也就不需要移动/拷贝元素:

int main()
{
    MyClass main(12);

    std::vector<MyClass2> ts;
    ts.reserve(10); // 提前预留10个元素的容量

    for (int i = 0; i < 10; ++i)
    {
        ts.emplace_back(main);
    }

    printf("%i\n", ts[0].my->x);

    return 0;
}

方案3:实现深拷贝的拷贝构造函数(如果需要拷贝语义)

如果你需要MyClass2支持拷贝(而不是移动),可以手动实现深拷贝的拷贝构造函数:

struct MyClass2
{
    std::unique_ptr<MyClass> my;

    MyClass2(const MyClass& my2)
    {
        my.reset(new MyClass(my2.x));
    }
    
    ~MyClass2()
    {
        printf("deleting\n");
    }

    // 深拷贝构造函数
    MyClass2(const MyClass2& other) : my(new MyClass(*other.my)) {}
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 18:53:19