c++11--强枚举类型,智能指针

发布时间:2026/7/30 17:16:35

c++11--强枚举类型,智能指针 1.枚举1.1.c11之前的枚举实例#include iostream enum Type{ ONE, TWO, THREE }; int main(){ printf(sizeof_%d, ONE_%d\n, sizeof(ONE), ONE); return 0; }具备以下特点(1). 枚举值直接在父作用域可见。(2). 枚举底层类型由编译器结合枚举成员数值自行决定。(3). 枚举值支持隐式转换为整数类型。称上述枚举为弱类型枚举。1.2.c的强类型枚举实例#include iostream enum Type{ ONE, TWO, THREE }; enum class TypeNew : char{ ONEN, TWON, THREEN }; int main(){ printf(sizeof_%d, ONE_%d\n, sizeof(ONE), ONE); printf(sizeof_%d,ONE_%d\n, sizeof(TypeNew::ONEN), TypeNew::ONEN); return 0; }具备以下特点(1). 枚举值直接在父作用域不可见需要通过形如上述TypeNew::ONEN的形式。(2). 枚举底层类型默认由编译器结合枚举成员数值自行决定但可在定义时指定如上述TypeNew底层类型为char。(3). 枚举值不支持隐式转换为整数类型。称上述为强枚举类型。1.3.c11对原弱枚举类型的增强(1). 支持对弱类型枚举指定底层存储类型。(2). 对弱枚举类型值在父作用域可见但也可通过枚举名::枚举值形式的使用。1.4.弱枚举类型和#define的差异#include iostream #define ONE 1 enum type{ ONE1 }; int main(){ ONE; ONE1; //int ONE 1; //int ONE1 11; printf(one1_%d\n, ONE1); return 0; }上述采用#define时main中int ONE 1;会报错。因为#define在预处理阶段执行简单替换。上述采用enum时main中int ONE1 11;不会报错后续打印的ONE1为11。因为enum在编译阶段编译器结合场景智能选择。2.智能指针2.1.unique_ptr实例#include memory #include iostream using namespace std; int main(){ unique_ptrint up1(new int(11)); //unique_ptrint up2 up1;// err cout *up1 endl; unique_ptrint up3 std::move(up1); cout *up3 endl; //cout *up1 endl;// err up3.reset(); up1.reset(); //cout *up3 endl;//err return 0; }(1).unique_ptr只支持移动拷贝构造移动赋值。移动拷贝下左边对象窃取右边对象资源。移动赋值下左边对象先释放底层资源再窃取右边对象资源。(2).unique_ptr对象持有的资源被窃取后后续不可再使用底层资源。(3). 可使用reset显式释放底层资源。底层资源释放后无法再使用。unique_ptr一般用于只有一个持有者的资源的管理。2.2.share_ptr实例#include memory #include iostream using namespace std; int main(){ shared_ptrint sp1(new int(22)); shared_ptrint sp2 sp1; cout *sp1 endl; cout *sp2 endl; sp1.reset(); cout *sp2 endl; return 0; }(1).shared_ptr支持普通拷贝构造普通赋值。普通拷贝构造下左边对象和右边对象共享同一底层对象。普通赋值下 左边对象原来底层对象的引用数先减1再和右边对象共享同一底层对象递增右边对象底层对象的引用数。(2).shared_ptr支持移动拷贝构造移动赋值。移动拷贝构造下右边对象底层资源被窃取到左边。意味着右边对象此后不可再访问底层资源。底层资源引用数并未增加和减少。移动赋值下先递减原来持有的底层资源引用数再窃取右边对象的底层资源。意味着右边对象此后不可再访问底层资源。但底层资源引用数并未增加和减少。(3). 底层对象被多个shared_ptr共享时通过共享的任一shared_ptr均可访问底层资源。单个shared_ptr释放资源只使得底层资源引用数减去1当底层资源引用数变为0时才实际释放。2.3.weak_ptr实例#include memory #include iostream using namespace std; void Check(weak_ptrint wp){ shared_ptrint sp wp.lock(); if(sp ! nullptr){ cout still *sp endl; } else{ cout pointer is invalid. endl; } } int main(){ shared_ptrint sp1(new int(22)); shared_ptrint sp2 sp1; weak_ptrint wp sp1; cout *sp1 endl; cout *sp2 endl; Check(wp); sp1.reset(); cout *sp2 endl; Check(wp); sp2.reset(); Check(wp); return 0; }(1).可通过一个shared_ptr来构造一个weak_ptr。(2).weak_ptr仅仅指向底层资源但无需递增底层资源引用数。(3).通过weak_ptr执行lock在指向的底层资源存在下返回一个shared_ptr。在指向的底层资源不存在下返回nullptr。3.智能指针的线程安全性以shared_ptr为例该类型智能指针内部既要记录对象指针 又要记录关于对象的引用。其中通过原子变量操作对象引用来保持多线程下对象引用修改的原子性。但我们执行诸如shared_ptrintpa(newint(1));shared_ptrintpb(newint(10));// 对pa需要// 递减原引用数// 判断引用数是否为0为0则释放原对象指针// 开始持有新的对象指针新的引用数指针。// 引用数加1。papb;上述过程引用数修改是原子的但整个操作是无锁的。所以多线程下需要对其加锁来保证整个过程互斥性。2.4.shared_ptr的循环引用与weak_ptr打破循环引用问题本质shared_ptr 使用引用计数管理内存。当两个对象互相持有对方的 shared_ptr 时引用计数永远不会归零导致内存泄漏。#includememory#includeiostreamclassB;// 前置声明classA{public:std::shared_ptrBb_ptr;// 持有 B 的强引用~A(){std::coutA destroyed\n;}};classB{public:std::shared_ptrAa_ptr;// 持有 A 的强引用~B(){std::coutB destroyed\n;}};intmain(){autoastd::make_sharedA();autobstd::make_sharedB();a-b_ptrb;// B 的引用计数 1 → 2b-a_ptra;// A 的引用计数 1 → 2// main 结束a 和 b 离开作用域// A 的引用计数: 2 → 1 (不为0不释放)// B 的引用计数: 2 → 1 (不为0不释放)// 循环引用 → 内存泄漏析构函数不会调用}输出空没有任何对象被销毁weak_ptr 打破循环weak_ptr 是弱引用它不增加引用计数只观测对象是否存在。当需要访问对象时通过 lock() 临时提升为 shared_ptr。#includememory#includeiostreamclassB;classA{public:std::weak_ptrBb_weak;// 改为 weak_ptr不增加 B 的引用计数~A(){std::coutA destroyed\n;}voiduseB(){// weak_ptr 使用前必须 lock() 检查对象是否存活if(autobb_weak.lock()){std::coutB is still alive, using it...\n;}else{std::coutB has been destroyed\n;}}};classB{public:std::shared_ptrAa_ptr;// B 仍然可以强引用 A~B(){std::coutB destroyed\n;}};intmain(){autoastd::make_sharedA();autobstd::make_sharedB();a-b_weakb;// B 的引用计数不变仍为 1b-a_ptra;// A 的引用计数 1 → 2// main 结束// b 离开作用域 → B 引用计数 1 → 0 → B 析构// B 析构时a_ptr 释放 → A 引用计数 2 → 1// a 离开作用域 → A 引用计数 1 → 0 → A 析构}输出B destroyed A destroyedweak_ptr 核心要点特性说明不控制生命周期不增加引用计数不影响对象释放可能失效引用的对象随时可能被释放安全访问必须通过lock()提升为shared_ptr返回空指针表示对象已销毁常用场景打破循环引用、缓存Cache实现、观察者模式2.5. shared_from_this 及其作用问题背景有时对象需要把自身的 shared_ptr 安全地传递给外部如注册回调、加入容器。但如果直接在构造函数或成员函数里用 shared_ptr(this)会创建一个独立的引用计数块导致双重释放。classBad:publicstd::enable_shared_from_thisBad{public:voiddangerous(){// ❌ 错误创建了一个新的控制块与外部已有的 shared_ptr 不共享引用计数std::shared_ptrBadself(this);// 当 self 和外部 shared_ptr 都释放时this 会被 delete 两次 → 未定义行为}};shared_from_this 的正确用法类必须公有继承 std::enable_shared_from_this然后调用 shared_from_this() 获取与外部共享同一控制块的 shared_ptr。#includememory#includeiostream#includevectorclassWorker:publicstd::enable_shared_from_thisWorker{public:voidstart(){// ✅ 正确获取的 shared_ptr 与外部已有的共享同一控制块std::shared_ptrWorkerselfshared_from_this();std::coutWorker started, use_count self.use_count()\n;// 安全地传递自身引用比如注册到线程池、事件循环、观察者列表// thread_pool.submit([self]() { self-doWork(); });}voiddoWork(){std::coutWorking...\n;}};intmain(){autowstd::make_sharedWorker();// 引用计数 1w-start();// start() 内 self 引用计数 2// start() 返回后 self 销毁引用计数回到 1// main 结束w 销毁引用计数 → 0正确释放}关键约束shared_from_this() 必须在 shared_ptr 管理下才能调用intmain(){Worker raw;// 栈对象没有被 shared_ptr 管理// ❌ 崩溃raw 不是由 shared_ptr 管理的没有控制块// auto self raw.shared_from_this();// 正确做法必须先被 shared_ptr 包装autowstd::make_sharedWorker();autoselfw-shared_from_this();// ✅ 安全}常见陷阱构造函数中调用 shared_from_this()classTrap:publicstd::enable_shared_from_thisTrap{public:Trap(){// ❌ 危险构造函数执行时shared_ptr 尚未完全构造完毕// auto self shared_from_this(); // 可能抛 std::bad_weak_ptr 异常}};// 正确做法在对象构造完成后由外部调用或在单独的 init() 中调用classSafe:publicstd::enable_shared_from_thisSafe{public:voidinit(){autoselfshared_from_this();// ✅ 此时对象已被 shared_ptr 管理// 注册回调、加入容器等}};autosstd::make_sharedSafe();s-init();// 安全shared_from_this 核心要点要点说明继承要求必须public std::enable_shared_from_thisT调用前提对象必须已被shared_ptr管理栈对象不行返回值shared_ptrT与外部共享同一控制块和引用计数异常安全若对象未被shared_ptr管理抛出std::bad_weak_ptr典型场景注册回调、异步操作持有自身引用、树形结构中父节点传引用给子节点一个完整工程示例异步任务持有自身#includememory#includeiostream#includethread#includechronoclassTask:publicstd::enable_shared_from_thisTask{public:voidrunAsync(){// 捕获 shared_ptr 而非原始 this确保异步执行期间对象存活autoselfshared_from_this();std::thread([self](){std::this_thread::sleep_for(std::chrono::seconds(1));// 如果这里用原始 this而外部已释放对象就是悬空指针self-finish();}).detach();}voidfinish(){std::coutTask finished safely\n;}};intmain(){{autotaskstd::make_sharedTask();task-runAsync();// task 引用计数 1self// task 离开作用域但 self 还在线程 lambda 中对象不会释放}std::this_thread::sleep_for(std::chrono::seconds(2));// 线程结束self 销毁引用计数归零对象安全释放}

相关新闻