面试:为什么智能指针避免传入裸指针?

📌 为什么智能指针避免传入裸指针?

在 C++11 及之后的标准中,智能指针(std::unique_ptrstd::shared_ptr)被引入 替代裸指针(raw pointer,T*,提供自动化内存管理,避免手动 delete 带来的内存泄漏和悬挂指针(dangling pointer)

然而,在使用智能指针时,不推荐直接传入裸指针(T*,尤其是在 std::shared_ptr 中,主要是因为可能导致“重复释放(double delete)”问题


📌 1. 为什么 std::shared_ptr<T> 不能直接传入裸指针?

🚨 直接使用 new 创建的裸指针传入 std::shared_ptr<T> 可能会导致 double delete,引发未定义行为(UB,Undefined Behavior)。

✅ 1️⃣ 正确使用 std::make_shared()

#include <iostream>
#include <memory>

struct MyClass {
    MyClass() { std::cout << "Constructor\n"; }
    ~MyClass() { std::cout << "Destructor\n"; }
};

int main() {
    std::shared_ptr<MyClass> sp1 = std::make_shared<MyClass>(); // ✅ 正确
    std::shared_ptr<MyClass> sp2 = sp1; // ✅ 共享所有权,正确
}

std::make_shared<T>() 更安全,避免 double delete 问题。


❌ 2️⃣ 直接传入 new 的裸指针,可能导致 double delete

#include <iostream>
#include <memory>

struct MyClass {
    MyClass() { std::cout << "Constructor\n"; }
    ~MyClass() { std::cout << "Destructor\n"; }
};

int main() {
    MyClass* raw = new MyClass();
    std::shared_ptr<MyClass> sp1(raw); // 🚨 `sp1` 负责释放 `raw`
    std::shared_ptr<MyClass> sp2(raw); // 🚨 `sp2` 也负责释放 `raw`,double delete!
}

🚨 问题:

  1. sp1 拿到 raw 的所有权,并在 sp1use_count == 0 时释放 raw
  2. sp2 重复持有 raw,导致 sp2 也在析构时释放 raw
  3. 最终 rawdelete 两次,产生未定义行为!

📌 2. 为什么 std::make_shared<T>() 更安全?

std::make_shared<T>() 分配单个内存块,减少分配开销,并避免 double delete

✅ 内存布局

❌ 直接 new 的情况
[std::shared_ptr]   -> [control block]
[std::shared_ptr]   -> [control block]
[raw pointer]       -> [对象数据]

📌 不同的 shared_ptr 实例可能管理相同 raw pointer,导致 double delete

std::make_shared<T>() 的情况
[std::shared_ptr]   -> [control block + 对象数据]
[std::shared_ptr]   -> [control block + 对象数据]

📌 对象和控制块在同一块内存中,引用计数清零时自动释放。


📌 3. 为什么 std::unique_ptr<T> 不能传入已存在的裸指针?

std::unique_ptr<T> 是独占所有权(Ownership),它不能共享一个 T*

✅ 正确的 std::unique_ptr<T>

#include <iostream>
#include <memory>

struct MyClass {
    MyClass() { std::cout << "Constructor\n"; }
    ~MyClass() { std::cout << "Destructor\n"; }
};

int main() {
    std::unique_ptr<MyClass> up1 = std::make_unique<MyClass>(); // ✅ 推荐
    std::unique_ptr<MyClass> up2 = std::move(up1); // ✅ 通过 `move` 转移所有权
}

❌ 传入已存在的 new 指针

MyClass* raw = new MyClass();
std::unique_ptr<MyClass> up1(raw);
std::unique_ptr<MyClass> up2(raw); // 🚨 两个 `unique_ptr` 管理相同 `raw`,double delete!

🚨 up1up2 都会在析构时 delete raw,导致 double delete


📌 4. 什么时候应该传裸指针?

📌 可以安全地传递 T*std::shared_ptr<T>,但前提是指针不再被 delete

void foo(std::shared_ptr<MyClass> sp) { }

int main() {
    std::shared_ptr<MyClass> sp = std::make_shared<MyClass>();
    foo(sp); // ✅ 传递 `shared_ptr`,不会导致 double delete
}

🚨 不要手动 new 一个裸指针然后传递给多个 shared_ptr


📌 5. 总结

智能指针管理对象生命周期,裸指针不能重复管理相同对象
不要直接传递 new 出来的裸指针给多个 shared_ptr,使用 std::make_shared<T>() 代替
std::unique_ptr<T> 不能共享所有权,传递时必须 std::move()
如果必须传裸指针,确保 new 出来的对象不会被多个 shared_ptr 直接管理

🚀 如果你在 C++ 编程中想避免内存泄漏和 double delete,使用 std::make_shared<T>() 是最好的选择!🔥

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值