[C++面试] 智能指针面试点(重点)续4

一、进阶

1、智能指针相互间赋值

1.1 unique_ptr 之间的赋值

左值不能直接赋值unique_ptr 表示独占所有权,禁止普通左值之间的赋值,避免多个指针指向同一对象。

cpp 复制代码
unique_ptr<int> a = make_unique<int>(5);  
unique_ptr<int> b;  
b = a; // 编译错误,a 是左值,直接赋值违反独占原则  

右值可通过移动赋值 :若为右值(如临时对象或通过 std::move 转换),则可移动赋值。此时原 unique_ptr 失去所有权(变为 nullptr

cpp 复制代码
unique_ptr<int> a = make_unique<int>(5);  
unique_ptr<int> b = std::move(a); // 合法,a 变为 nullptr,b 接管对象 
1.2 unique_ptrshared_ptr 的赋值

unique_ptr 右值可赋值给 shared_ptrshared_ptr 有显式构造函数,可接收 unique_ptr 右值(如临时对象或 std::move 转换后的对象)。此时 shared_ptr 接管对象所有权:

cpp 复制代码
unique_ptr<int> uptr = make_unique<int>(10);  
shared_ptr<int> sptr1 = std::move(uptr); // 合法,uptr 变为 nullptr  

shared_ptr<int> sptr2(make_unique<int>(20)); // 合法,临时 unique_ptr 作为右值  
shared_ptr<int> sptr3 = make_unique<int>(42); // 隐式移动构造。在构造shared_ptr时传入unique_ptr的右值(如函数返回值),编译器会自动完成移动操作

unique_ptr 左值不可直接赋值给 shared_ptr :若直接用 unique_ptr 左值初始化 shared_ptr,会编译错误

cpp 复制代码
unique_ptr<int> uptr = make_unique<int>(10);  
shared_ptr<int> sptr3(uptr); // 编译错误,uptr 是左值  
1.3 总结
  • 允许转换的方向unique_ptrshared_ptr(通过移动语义)。
  • 禁止转换的方向shared_ptrunique_ptr
  • unique_ptr 之间仅允许右值移动赋值;unique_ptr 可通过右值(如 std::move 或临时对象)赋值给 shared_ptr,但左值不行。

2、 shared_ptr<int*>有什么问题?

cpp 复制代码
// 正确用法:shared_ptr<int> 管理 int 对象  
shared_ptr<int> sp1 = make_shared<int>(10); // 直接管理 int 值 10  

// 非常规用法:shared_ptr<int*> 管理 int* 指针
// 管理 int*,需确保 int* 指向的内存正确释放(此处虽合法但不推荐)    
shared_ptr<int*> sp2 = make_shared<int*>(new int(20)); 

shared_ptr<int> :直接管理一个 int 类型的对象,智能指针内部存储的是 int 对象的指针(如 int*),并负责该 int 对象的内存释放。符合智能指针的设计初衷,直接管理对象内存。

shared_ptr<int*> :管理一个 int* 类型的指针(即指针本身成为智能指针管理的对象)。这种用法违背了智能指针简化对象管理的原则,因为 int* 指向的对象仍需确保其生命周期正确(虽然此处 int*new int 分配,delete 合法,但代码逻辑易混淆)。

cpp 复制代码
std::shared_ptr<int*> sptr(
    new int*(new int(42)), 
    [](int** p) { 
        delete *p;  // 释放内层 int 对象
        delete p;    // 释放外层 int* 指针
    }
);

需在自定义删除器中显式释放内层内存。


使用 shared_ptr<T[]>(C++17 及以上)

cpp 复制代码
int main() {
    // 创建 shared_ptr 管理动态数组(C++17 起支持)
    std::shared_ptr<int[]> arr(new int[5]{1, 2, 3, 4, 5});

    // 直接通过 operator[] 访问元素
    for (int i = 0; i < 5; ++i) {
        arr[i] = i * 10;        // 修改元素
        std::cout << arr[i] << " ";  // 输出:0 10 20 30 40
    }

    // 无需手动释放,shared_ptr 自动调用 delete[]
    return 0;
}

自定义删除器(兼容 C++11/14)

cpp 复制代码
int main() {
    // 定义删除器(Lambda 表达式)
    auto array_deleter = [](int* ptr) {
        delete[] ptr;  // 必须显式调用 delete[]
        std::cout << "动态数组内存已释放\n";
    };

    // 创建 shared_ptr 并传入删除器
    std::shared_ptr<int> arr(new int[5]{1, 2, 3, 4, 5}, array_deleter);

    // 通过 get() 获取原始指针访问元素
    int* raw_ptr = arr.get();
    for (int i = 0; i < 5; ++i) {
        raw_ptr[i] = i * 10;       // 修改元素
        std::cout << raw_ptr[i] << " ";  // 输出:0 10 20 30 40
    }

    // 析构时自动调用 array_deleter
    return 0;
}
相关推荐
oqX0Cazj2几秒前
2026超火Go-Zero实战:从架构原理到高并发接口落地,彻底解决接口超时、雪崩问题
开发语言·架构·golang
蝎子莱莱爱打怪2 分钟前
XZLL-IM干货系列 02|Protobuf 协议设计:从 JSON 切到二进制,每条消息省了 60%
后端·面试·架构
学会去珍惜4 分钟前
C语言简介
c语言·开发语言
卷帘依旧7 分钟前
输入 URL 到页面展示速记版
面试
思麟呀7 分钟前
C++11 核心特性(三):强类型枚举、static_assert 与 std::tuple
开发语言·c++
hoiii18714 分钟前
Qt 实现屏幕截图功能
开发语言·qt·命令模式
一拳一个呆瓜19 分钟前
【STL】C++程序的启动与终止
c++·stl
小白学大数据33 分钟前
爬虫性能天花板:asyncio赋能 Aiohttp,并发提速 10 倍
开发语言·爬虫·数据分析
凡人叶枫43 分钟前
Effective C++ 条款07:为多态基类声明 virtual 析构函数
linux·c语言·开发语言·c++
凡人叶枫1 小时前
Effective C++ 条款10:令 operator= 返回一个 reference to *this
java·linux·服务器·开发语言·c++·effective c++