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
相关产品推荐
相关产品推荐

