今天,我们将深入探讨std::unique_ptr的灵魂组件——自定义删除器,并揭示其如何将RAII模式泛化到任何一种资源,以及其背后深刻的类型系统哲学。...高级应用场景:超越“释放”自定义删除器的能力远不止调用一个关闭函数。它可以封装复杂的策略,成为设计中的重要一环。...场景三:模拟finally在异常安全编程中,确保资源在任何路径(包括异常抛出)下都能被释放至关重要。自定义删除器是实现这一目标的完美工具。...编译时多态:通过将删除器作为模板参数,我们获得了编译时多态的能力。编译器能够看到完整的删除操作,并进行积极的优化(如内联)。...结语当我们超越std::unique_ptr的表面,深入探究其自定义删除器机制时,我们看到的不仅仅是一个方便的工具,而是一套完整的、可扩展的资源管理范式。
核心优势自动资源管理:无需手动调用 delete,降低内存泄漏风险异常安全:即使在异常抛出的情况下,仍能保证资源正确释放移动语义支持:可通过移动操作转移所有权,避免浅拷贝问题自定义删除器:支持非默认的资源释放逻辑...} // 其他成员函数与单对象版本类似...};2.3 关键技术点解析删除器设计默认使用 DefaultDeleter,对单对象使用 delete,对数组使用 delete[]支持自定义删除器...// 数组版本会自动使用 delete[] 释放资源3.3 自定义删除器当管理非内存资源(如文件句柄、网络套接字)时,可使用自定义删除器:#include // 自定义文件删除器struct...std::cout 自定义删除器的 unique_ptr std::unique_ptr...:转移所有权 // auto ptr3 = ptr2; // 错误:禁止拷贝正确处理数组使用 unique_ptr 特化版本避免使用 unique_ptr 管理数组自定义删除器注意事项当使用函数指针作为删除器时
自定义删除器可指定自定义删除逻辑(如关闭文件、释放资源等)。...cpp运行// 自定义删除器(例如关闭文件)auto file_deleter = [](FILE* fp) { if (fp) fclose(fp); };std::unique_ptr自定义删除器与 unique_ptr 类似,可指定自定义删除逻辑(如关闭文件、释放资源):cpp运行auto file_deleter = [](FILE* fp) { if (fp) fclose(fp...unique_ptr和share_ptr都支持删除器问题出在智能指针默认的删除器不匹配动态数组的内存释放逻辑,导致程序崩溃或内存错误默认删除器会调用 delete 而非 delete[]delete 用于释放单个对象...) atomic* _pcount; // 原子类型的引用计数器,保证线程安全 // 删除器,默认使用delete操作符 // 可以通过构造函数自定义删除操作
这意味着你可以自定义删除器,并告诉 unique_ptr 你希望使用什么类型的“指针”。如果你的删除器没有定义 pointer 类型,那么默认就是 _Tp*。...这一步完成了所有权的“释放”。std::forward(u.get_deleter()): 完美转发删除器。如果删除器支持移动构造,就移动它;否则,拷贝它。...如果不为空,就调用存储的删除器来释放资源。这一切都是自动发生的,用户无需手动 delete。...四、总结:平凡中的非凡通过剖析源码,我们看到 std::unique_ptr 并非魔法:它本质上只是一个包裹了“原始指针 + 删除器”的类。...利用模板和元编程(std::remove_reference)提供了极大的灵活性,支持自定义删除器和仿指针类型。在析构函数中调用删除器,完美践行了 RAII 理念。它的美正在于这种“平凡”。
特点 独占所有权:不能复制,但可以通过移动语义转移所有权。 自定义删除器:可以指定一个自定义的删除函数或lambda表达式来替代默认的delete操作。...数组支持:std::unique_ptr专门用于管理动态分配的数组,其析构函数会调用delete[]来释放内存。 2.2....自定义删除器:同unique_ptr,可以指定自定义删除函数。 循环引用问题:需要小心处理,可能会导致内存泄漏。 3.2....为了避免循环引用,可以使用std::weak_ptr来替代其中一个shared_ptr。 5.3. 谨慎使用自定义删除器 虽然智能指针允许指定自定义删除器,但应谨慎使用。...自定义删除器可能会引入额外的复杂性和错误风险。在大多数情况下,使用默认的delete操作就足够了。 5.4.
独占所有权的指针在释放时直接删除对象,共享所有权的指针则在最后一个指针释放时删除对象。...考虑一种情况:如果一个函数同时出现了unique_ptr和unique_ptr的重载,并且尝试通过隐式转换调用,那么编译器无法推测应该转换为哪种类型。...像不支持自定义分配器,不支持自定义析构器,不支持weak_ptr,不支持shared_ptr别名,不支持工厂函数构建等等,可优化空间很多。...--- 浅总结一下智能指针知识点 shared_ptr一般比unique_ptr更占用内存,但是如果在unique_ptr使用自定义析构器的话,那么情况可能不同。...如下场景不适合或谨慎使用make工厂函数: 自定义析构器。工厂函数无法自定义析构器,所以这种场景就无法使用。
):需要调用特定函数释放(如:fclose、closesocket) 自定义的资源释放逻辑(如:日志记录、状态清理等) 此时,默认的 delete 无法满足需求,必须通过自定义删除器来指定资源的释放方式...(T* ptr) //注意:数组中元素的类型(此处为Resource) { if (ptr) //安全检查:避免对空指针执行释放操作 { //1.显示使用自定义删除器释放数组的提示...1. unique_ptr自动调用绑定的lambda_deleter删除器 * 2. lambda删除器先打印"用 lambda 释放数组" * 3....--------- 解决方案2.1:自定义删除器(函数指针版本)--------------*/ //1. unique_ptr需指定函数指针类型作为模板参数 unique_ptr数组特化版本:调用delete[] * 2. 自定义删除器版本调用:对应的函数/仿函数/lambda * 3.
自定义删除器的用途 通常情况下,std::unique_ptr 和 std::shared_ptr 会在其析构时调用 delete 或 delete[] 来释放资源。...使用 std::unique_ptr 的自定义删除器 std::unique_ptr 支持通过模板参数指定删除器类型,可以为其传递自定义的删除器函数或函数对象。...使用 std::shared_ptr 的自定义删除器 std::shared_ptr 同样支持自定义删除器。...与 std::unique_ptr 不同的是,std::shared_ptr 的删除器是通过构造函数传递的,而不是作为模板参数。...std::shared_ptr 离开作用域时会调用此删除器,确保资源被正确释放。 4. 自定义删除器的优点 灵活性:允许管理非内存资源(如文件句柄、数据库连接)。
例如: int x; unique_ptr up(&x); // 错误,会尝试delete栈变量 智能指针支持在构造时指定删除器——一个可调用对象,用于自定义资源释放方式。...智能指针支持在构造时指定删除器——一个可调用对象,用于自定义资源释放方式。例如: 1....默认行为与自定义行为无缝切换 默认使用 delete ptr 释放资源 用户可提供自定义删除器覆盖默认行为 3....和boost::scoped_ptr 通过删除拷贝构造函数确保独占所有权 支持移动语义(std::move) 可自定义删除器 shared_ptr/weak_ptr:与boost版本基本兼容 改进示例...// 自定义删除器 auto deleter = [](FILE* fp){ fclose(fp); }; std::unique_ptr file(
与静态内存(由编译器在编译时分配)和自动内存(由编译器在函数调用时自动分配和释放)不同,动态内存提供了更大的灵活性和控制能力。...动态内存管理需要特别注意以下几点: 必须手动释放通过 new 分配的内存,以防止内存泄漏。 不能重复释放已经释放的内存,这会导致未定义的行为。...return 0; } 二维数组示例: #include using namespace std; int main() { int **p;...<<endl; } }; int main( ) { Box* myBoxArray = new Box[4]; delete [] myBoxArray; // 删除数组...std::unique_ptr 是 C++11 引入的智能指针,它具有独占性质。一个 std::unique_ptr 拥有对其所指向对象的唯一所有权,并在其生命周期结束时自动释放内存。
核心优势共享所有权:支持多指针共同管理同一资源自动释放:最后一个所有者销毁时自动释放资源灵活性:可与标准容器和算法无缝配合线程安全:引用计数的修改是原子操作,支持多线程环境自定义删除器:支持自定义资源释放逻辑二...shared_ptr 支持自定义删除器,用于非默认的资源释放逻辑:#include // 自定义文件删除器struct FileDeleter { void operator()(..."; } }};int main() { // 使用自定义删除器管理文件指针 std::shared_ptr file_ptr( std::fopen...17 前 shared_ptr 不直接支持数组,需提供自定义删除器 // C++17 前管理数组的正确方式 std::shared_ptr arr_ptr(new int[5], std...其核心特点包括:共享所有权:多个 shared_ptr 可指向同一对象自动释放:最后一个所有者销毁时释放资源线程安全:引用计数操作是原子的,支持多线程环境灵活性:支持自定义删除器和分配器配合 weak_ptr
*count : 0; } }; 对比表格:空实现 vs 标准库实现 特性 空实现 标准库实现 基础内存管理 ✓ ✓ 移动语义 ✓ ✓ 引用计数 ✓ (shared_ptr) ✓ 自定义删除器 ✗ ✓...数组支持 ✗ ✓ (unique_ptr) 原子操作 ✗ ✓ (shared_ptr) 类型转换 ✗ ✓ (const_pointer_cast等) weak_ptr支持 ✗ ✓ make_shared...uptr) { std::cout << "uptr is now empty\n"; } } // uptr2 超出作用域,资源释放...Resource created Use count: 1 Use count: 2 Using resource Use count: 1 Resource destroyed 关键区别说明 自定义删除器...: 标准库实现支持自定义删除器 空实现使用固定的 delete 操作符 数组支持: 标准库 unique_ptr 支持 unique_ptr 空实现不支持数组类型 线程安全:
删除器的基本概念 在C++中,智能指针(Smart Pointers)如std::unique_ptr和std::shared_ptr默认使用delete或delete[]来释放内存。...1.1 默认删除器 默认情况下,std::unique_ptr和std::shared_ptr使用以下方式进行删除: delete ptr; delete[] arr_ptr; 这些删除器在大多数情况下都很有用...当你想管理一个不是通过new分配的对象,例如一个栈上的对象或一个全局变量。 当你想管理一个不是单个对象而是一个数组或容器的对象。...1.2.3 异常安全 自定义删除器有助于实现异常安全(Exception Safety)。当构造函数可能抛出异常时,使用智能指针和自定义删除器可以确保资源被正确释放。...std::unique_ptr或std::shared_ptr的删除器。
资源析构采用 delete 运算符来实现,但可以指定自定义删除器 // 有状态的删除器和采用函数指针实现的删除器会增加 std::unique_ptr // 别的对象尺寸 // • std::unique_ptr...operator 重载了 [] 运算符,当 unique_ptr 指针指向一个数组时,可以直接通过 [] 获取指定下标位置处的数据。...{pw1, pw2 //但是请注意:对于具有不同自定义析构器型别的 std::unique_ptr来说,以上这些均无法实现 //因为自定义析构器的型别会影响 std::unqie_ptr的型别 //不同点...的尺寸通常是裸指针尺寸的两 // 倍,它还会带来控制块的开销,并要求原子化的引用计数操作 // • 默认的资源析构通过 delete 运算符进行,但同时也支持定制删除器。...::make_unique , 利用C++11实现一个基础版本的 std::make_unique //将形参向待创建对象的构造函数作了一次完美转发,并返回一个指涉到该对象的智能指针 //这个形式的函数不支持数组和自定义析构器
智能指针的删除器 智能指针默认使用 delete 释放资源,因此不能直接用于管理非 new 分配的资源,否则会导致 delete 释放非法内存。...unique_ptr 和 shared_ptr 支持自定义删除器,即在构造时传入一个可调用对象(函数、lambda、仿函数),来指定资源释放方式。...例如 new[] 需要 delete[] 释放,因此 unique_ptr 和 shared_ptr 也特化了数组版本。...的删除器类型。...支持自定义删除器,适用于 new[] 和非 new 资源。 智能指针让 C++ 资源管理更加 自动化、安全、高效,是现代 C++ 编程的最佳实践之一!
二、智能指针概述智能指针本质上是封装了裸指针的类,通过 RAII(资源获取即初始化)管理资源生命周期。常见智能指针: std::unique_ptr:独占所有权,不能复制,只能移动。... p2 = std::move(p1);// p1 失效,p2 拥有所有权3.3 自动释放机制智能指针析构时调用 delete 释放内存,避免泄漏。...3.4 自定义删除器cpp复制编辑std::unique_ptr fp(fopen("file.txt", "r"), &fclose);支持管理非 new...六、智能指针的内部实现原理6.1 Control Block 结构 持有资源指针 强引用计数 弱引用计数 删除器指针(自定义删除器) 6.2 引用计数操作线程安全的计数增加和减少,通常使用原子操作...7.2 使用 unique_ptr 表达独占语义避免无谓的引用计数开销。7.3 注意循环引用用 weak_ptr 打破循环。7.4 自定义删除器管理非内存资源管理文件、socket 等资源。
T的数组对象 unique_ptr up(); //空的unique_ptr,接受一个D类型的删除器D,使用D释放内存 unique_ptr up(new T()); //定义unique_ptr...,同时指向类型为T的对象,接受一个D类型的删除器d,使用删除器d来释放内存 删除器 利用一个仿函数实现一个删除器 class DestructTest { public: void operator...(void) { //使用自定义的删除器 unique_ptrup(new Test()); return 0; } 赋值 (接管所有权)一定要使用移动语义...;//指向类型为T的数组对象 C++17后支持 shared_ptr sp4(NULL, D()); //空的shared_ptr,接受一个D类型的删除器,使用D释放内存 shared_ptr... sp5(new T(), D()); //定义shared_ptr,指向类型为T的对象,接受一个D类型的删除器,使用D删除器来释放内存 数组对象的管理: shared_ptr
std::unique_ptr 简单说,当我们独占资源的所有权的时候,可以使用 std::unique_ptr 对资源进行管理——离开 unique_ptr 对象的作用域时,会自动释放资源。...delete p; // 要记得释放内存 } 使用 std::unique_ptr 自动管理内存。...(uptr == nullptr); } std::unique_ptr 可以指向一个数组。...} // use_count 为 0 时自动释放内存 和 unique_ptr 一样,shared_ptr 也可以指向数组和自定义 deleter。...image 当 shared_ptr 析构并释放共享资源的时候,只要 weak_ptr 对象还存在,控制块就会保留,weak_ptr 可以通过控制块观察到对象是否存活。 ?
Use std::unique_ptr for exclusive-ownership resource management 默认情况下(不传入自定义析构器时), std::unique_ptr 和原始指针大小一样...std::unique_ptr 设置自定义析构器后, std::unique_ptr 的大小不再等于原始指针的大小 当自定义析构器是函数指针时, std::unique_ptr 的大小从 1 个字长变为...2 个字长 当自定义析构器是函数对象时, std::unique_ptr 的大小取决于函数对象内部存储多少状态,无状态函数对象(例如:无捕捉的 lambda 表达式)不会增加 std::unique_ptr...有两种形式,一种是针对单个对象( std::unique_ptr ),另一种是针对数组( std::unique_ptr ),针对单个对象时,不能使用 运算,而针对数组对象时不能使用...自定义的析构器区别 对于 std::unique_ptr ,自定义析构器属于 std::unique_ptr 的一部分 对于 std::shared_ptr ,自定义析构器不属于 std::unique_ptr
因此,在使用 detach() 方法时应谨慎 自定义删除器 智能指针:能够保证资源的绝对释放,里面默认都是delete ptr释放资源的 但不是所有的资源都是能够通过delete释放的,毕竟资源那么多种类...比如我用智能指针托管数组的话,那delete就不行,得用delete[] 再比如我让它管理的不是内存资源,而是文件资源,那释放文件也绝对不可能用delete释放的 所以在我们除了智能指针在堆内存外,怎么正确指导智能指针来正确删除呢...先讲讲智能指针内部是咋回事吧 unique_ptr shared_ptr 一个不带计数,一个带计数 他们两个都是可以带自定义删除器的 看他们的源码 ~unique_ptr(){ 是一个函数对象的调用...第二个参数是删除器类型,即 function。删除器是一个函数对象,用于在智能指针销毁时释放其所指向的资源 在这段代码中,删除器是一个 lambda 表达式。...这个 lambda 表达式接受一个 int 指针作为参数,并在其函数体中使用 delete[] 运算符来释放该指针所指向的数组 当 ptr1 被销毁时,它会调用这个 lambda 表达式来释放其所指向的数组