unique_ptr 智能指针
unique_ptr 智能指针
文章目录
- unique_ptr 智能指针
- `std::unique_ptr` 的特性
- 初始化
- 转移所有权(移动语义)
- 访问和修改资源
- 删除器
std::unique_ptr
是 C++ 标准库中的一部分,位于<memory>
头文件中。它的“唯一性”(unique
)意味着它是独占的,即一个资源(例如动态分配的内存)只能由一个unique_ptr
管理。
std::unique_ptr
的特性
- 独占所****有权:
std::unique_ptr
通过“独占所有权”来管理资源。每个unique_ptr
对象拥有它所指向的资源,且资源只能有一个unique_ptr
对象来管理。这意味着不能存在两个unique_ptr
同时指向同一个资源。 - 自动资源释放: 当
unique_ptr
被销毁时,它会自动释放所管理的资源。这消除了手动调用delete
或delete[]
的需要,大大减少了内存泄漏的风险。 - 不可复制、可移动:
unique_ptr
不允许复制(copy
),因此不能有多个unique_ptr
指向同一个对象。它只支持移动(move
),意味着你可以通过移动语义将资源的所有权从一个unique_ptr
转移到另一个。 - 与裸指针兼容: 虽然
unique_ptr
不能直接复制,但它可以通过get()
方法获取裸指针,并与其他裸指针函数兼容。get()
返回指向资源的原始指针,但不拥有资源的所有权。
初始化
std::unique_ptr是一个独占型的智能指针,它不允许其他的智能指针共享其内部的指针,可以通过它的构造函数初始化一个独占智能指针对象,但是不允许通过赋值将一个unique_ptr赋值给另一个unique_ptr。
// 创建一个unique_ptr
std::unique_ptr<int> ptr = std::make_unique<int>(10);// 创建一个int 的 unique_ptr 并使用自定义的 deleter
std::unique_ptr<int, std::function<void(int*)>> ptr2(new int(10), [](int *p){ cout<< "Deleting pointer: " << *p << endl;delete p; });
转移所有权(移动语义)
int main(){std::unique_ptr<int> ptr1 = std::make_unique<int>(10);std::unique_ptr<int> ptr2 = std::move(ptr1); // 转移所有权std::cout << *ptr2 << std::endl; // 输出10// ptr1 现在为空,无法再访问if (!ptr1) {std::cout << "ptr1 is now null" << std::endl;}}
通过
std::move
,ptr2
获得了ptr1
所管理的资源的所有权,ptr1
成为一个空指针。
访问和修改资源
可以使用
*
操作符来解引用unique_ptr
,访问它所管理的资源。
int main(){std::unique_ptr<int> ptr = std::make_unique<int>(20);// 通过解引用访问资源*ptr = 30;// 或者使用指针成员函数 get()std::cout << *ptr << std::endl; // 输出 30
}
删除器
unique_ptr指定删除器和shared_ptr指定删除器是有区别的,unique_ptr指定删除器的时候需要确定删除器的类型,所以不能像shared_ptr那样直接指定删除器,举例说明:
shared_ptr<int> ptr1(new int(10), [](int*p) {delete p; }); // ok
unique_ptr<int> ptr1(new int(10), [](int*p) {delete p; }); // errorint main()
{using func_ptr = void(*)(int*);unique_ptr<int, func_ptr> ptr1(new int(10), [](int*p) {delete p; });return 0;
}
在上面的代码中第7行,func_ptr的类型和lambda表达式的类型是一致的。在lambda表达式没有捕获任何变量的情况下是正确的,如果捕获了变量,编译时则会报错:
int main()
{using func_ptr = void(*)(int*);unique_ptr<int, func_ptr> ptr1(new int(10), [&](int*p) {delete p; }); // errorreturn 0;
}
上面的代码中错误原因是这样的,在lambda表达式没有捕获任何外部变量时,可以直接转换为函数指针,一旦捕获了就无法转换了,如果想要让编译器成功通过编译,那么需要使用可调用对象包装器来处理声明的函数指针:
int main()
{using func_ptr = void(*)(int*);unique_ptr<int, function<void(int*)>> ptr1(new int(10), [&](int*p) {delete p; });return 0;
}