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

C++如何通过BaseHolder接管main中Derived临时右值引用的所有权

报错原因

你当前的写法存在两个核心问题:

  • C++的容器存储的是类型实例本身,你声明的vector<Base> m_bases要求Base类型可以被实例化,但Base是包含纯虚函数的抽象类,本身就不允许创建独立实例。
  • 你传入Derived类的临时对象时,往vector<Base>插入的操作会触发对象切片:只会复制/移动对象中属于Base类的成员,尝试调用Base的拷贝/移动构造函数生成新的Base实例,这就是你触发非法构造调用报错的原因。
实现方案

你可以通过存储智能指针的方式接管派生类临时对象的所有权,既可以避免对象切片,也不需要实例化抽象基类,修改后的代码如下:

#include <vector>
#include <memory>
#include <type_traits>

using namespace std;

class Base {
public:
    virtual void foo() = 0;
    // 抽象基类声明虚析构函数,避免派生类内存泄漏
    virtual ~Base() = default;
};

class BaseHolder {
    // 改为存储Base的智能指针,不需要实例化Base
    vector<unique_ptr<Base>> m_bases;
public:
    // 模板完美转发,兼容直接传入派生类临时对象的调用写法
    template<typename T, typename = enable_if_t<is_base_of_v<Base, decay_t<T>>>>
    void add(T&& derived) {
        m_bases.emplace_back(make_unique<decay_t<T>>(forward<T>(derived)));
    }
    // 额外支持直接传入智能指针的重载,扩展性更强
    void add(unique_ptr<Base> base_ptr) {
        m_bases.push_back(move(base_ptr));
    }
};

class Derived : public Base {
public:
    void foo() override {}
};

int main() {
    BaseHolder base_holder;
    // 原调用方式完全兼容
    base_holder.add(Derived());
    // 也可以直接传入智能指针
    base_holder.add(make_unique<Derived>());
    return 0;
}
修改说明
  • 给Base类添加了默认虚析构函数,是C++多态场景的标准写法,避免派生类对象通过基类指针释放时发生内存泄漏。
  • 容器改为存储unique_ptr<Base>,仅保存指针地址,不需要实例化Base类,同时unique_ptr自带移动语义,完美匹配你要接管临时对象所有权的需求。
  • 新增的模板add函数兼容你原来的调用写法,自动完成派生类对象到unique_ptr<Base>的转换,也支持传入左值派生类对象,加enable_if限制仅接受Base的派生类,避免传错类型。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.15 09:06:04