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

std::unique_ptr与手动堆分配+delete的对比及优势问询

问题

假设存在基类B、子类B1和类A,需要将B1指针作为A的成员变量。可以通过手动堆分配B1并在A的析构函数中执行delete实现,示例代码如下:

class B {
    public:
        B() { };
};

class B1 : public B {
    public:
        B1() { };
};


class A {
    public:
         B* b_instance;

         A(B* b_instance){
             this->b_instance = b_instance;
         };

         ~A(){
             delete this->b_instance;
         };
};

int main() {
    B* b_instance = new B1();
    A a_instance(b_instance);
    return 0;
};

另一种更受青睐的方式是使用std::unique_ptr:将指向B1的unique_ptr交由A管理,作为智能指针,当A销毁时,因无引用B1会自动销毁。编写的示例代码如下:

#include <memory>

class B {
    public:
        B() { };
};

class B1 : public B {
    public:
        B1() { };
};


class A {
    public:
         std::unique_ptr<B> b_instance;

         A(B& b_instance){
             this->b_instance = std::make_unique<B>(b_instance);
         };

         ~A() { };
};

int main() {
    B1 b_instance;
    A a_instance(b_instance);
    return 0;
};

请问:只要记得在A的析构函数中delete成员指针,两种方式是否等价?std::unique_ptr还有其他优势吗?


解答

首先得指出你的代码里的两个关键问题:

  1. 基类B没有虚析构函数,直接delete基类指针指向的子类对象会触发未定义行为,这是手动管理和智能指针方式都必须修复的前提。
  2. 第二个std::unique_ptr示例逻辑错误:std::make_unique<B>(b_instance)是创建了一个基类B的拷贝对象,而非指向传入的B1实例,和第一个手动指针的逻辑完全不符。正确的写法应该是让A接管B1的智能指针所有权,比如:
#include <memory>

class B {
    public:
        virtual ~B() = default; // 添加虚析构
};

class B1 : public B {
    public:
        B1() { };
};

class A {
    public:
         std::unique_ptr<B> b_instance;

         // 通过移动语义接管unique_ptr的所有权
         A(std::unique_ptr<B> ptr) : b_instance(std::move(ptr)) {};
};

int main() {
    std::unique_ptr<B> b_instance = std::make_unique<B1>();
    A a_instance(std::move(b_instance));
    return 0;
};

一、两种方式是否等价?

即使修复了上述问题,手动管理指针和std::unique_ptr也不完全等价:

  • 手动管理需要确保在所有代码路径(比如构造函数抛异常、对象被拷贝/赋值)中都正确执行delete,稍有疏忽就会出现内存泄漏或重复释放;而std::unique_ptr的析构是自动触发的,不受代码分支影响。
  • 手动指针无法表达独占所有权的语义,其他开发者很难直观判断这个指针的生命周期由谁负责;std::unique_ptr则明确了它对指向对象的独占所有权,代码意图更清晰。

二、std::unique_ptr的额外优势

  • 自动内存安全:不管A的对象是正常销毁,还是因为构造函数抛异常中途退出,std::unique_ptr都会自动释放内存,彻底避免手动管理时遗漏delete导致的内存泄漏。
  • 杜绝非法拷贝:std::unique_ptr是不可拷贝的,从根源上避免了多个A对象持有同一个原始指针、进而重复释放的风险;而手动指针如果不小心被拷贝,很容易触发重复delete的崩溃。
  • 语义清晰直观:std::unique_ptr直接表达了“独占对象所有权”的意图,其他开发者一眼就能明白这个对象的生命周期由A负责,减少了沟通成本和理解偏差。
  • 无需手动写析构:使用std::unique_ptr后,A不需要手动编写析构函数,编译器会自动生成正确的析构逻辑,同时避免了手动写析构可能引入的问题(比如忘记加虚、遗漏清理逻辑)。
  • 适配标准库更安全:std::unique_ptr可以直接存入std::vector等标准容器,容器销毁时会自动清理内部的智能指针,无需手动遍历释放;而手动指针存入容器后,必须手动清理,极易出错。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 20:30:55