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

如何正确将std::unique_ptr<B>转换为std::unique_ptr<A>?

正确实现std::unique_ptr到std::unique_ptr的转换

问题背景

在C++中,裸指针B*可以隐式转换为A*,通过动态调度调用对应方法。但std::unique_ptr<B>无法直接隐式转换为std::unique_ptr<A>,手动提取裸指针封装成std::unique_ptr<A>会触发双删除问题:Printer函数返回时释放一次对象,main中bPtr销毁时再次释放同一对象。

原始问题代码:

#include <iostream>
#include <memory>

class A
{
public:
    virtual void Print() = 0;
};

class B : public A
{
public:
    void Print()
    {
        std::cout<<"Hello, world\n";
    }
};

void Printer(std::unique_ptr<A> aPtr)
{
    aPtr->Print();
}

int main()
{
    std::unique_ptr<B> bPtr = std::make_unique<B>();
    Printer(std::unique_ptr<A>(bPtr.get()));    // 导致双删除
    
}

解决方案

1. 使用std::move转移所有权

std::unique_ptr是独占式智能指针,通过std::move可以将std::unique_ptr<B>的所有权转移给std::unique_ptr<A>,此时原bPtr会变为空指针,不会再参与对象销毁,避免双删除。

修改后的main函数:

int main()
{
    std::unique_ptr<B> bPtr = std::make_unique<B>();
    Printer(std::move(bPtr)); // 所有权完全转移给Printer的参数,bPtr此后为空
}

2. 调整Printer函数参数(不转移所有权)

如果不需要转移对象所有权,仅临时调用方法,可修改Printer的参数类型:

方案2.1:接收std::unique_ptr<A>&引用
void Printer(std::unique_ptr<A>& aPtr)
{
    aPtr->Print();
}

int main()
{
    std::unique_ptr<B> bPtr = std::make_unique<B>();
    Printer(bPtr); // 传递引用,所有权仍保留在bPtr
}
方案2.2:直接接收裸指针

这种方式更简洁,适合仅调用方法、不涉及所有权管理的场景:

void Printer(A* aPtr)
{
    if (aPtr != nullptr) {
        aPtr->Print();
    }
}

int main()
{
    std::unique_ptr<B> bPtr = std::make_unique<B>();
    Printer(bPtr.get()); // 传递裸指针,所有权归bPtr所有
}

关键注意事项

必须确保基类A的析构函数为虚函数,否则当std::unique_ptr<A>销毁对象时,只会调用A的析构函数,无法触发B的析构逻辑,导致内存泄漏。修改后的A类定义:

class A
{
public:
    virtual void Print() = 0;
    virtual ~A() = default; // 添加虚析构函数
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 21:02:28