简介
智能指针是一种特殊的指针类型,它能够自动管理内存资源,避免常见的内存泄漏和多次释放等。在C++ 11标准中出现了新的智能指针unique_ptr、 shared_ptr、weak_ptr等。
std::unique_ptr
用于管理动态分配的内存资源,它提供了自动释放内存的功能。与原始指针相比,unique_ptr有更高的安全性和易用性。
特点: 所有权唯一、自动释放内存、指针语义、禁止拷贝和权限转移、自定义删除器
所有权唯一:每个unique_ptr实例拥有对其所指向对象的唯一所有权。这意味着在任何时候只有一个unique_ptr可以指向一个特定的对象。
自动释放内存:当unique_ptr超出作用域或被重新赋值时,它所管理的内存会自动释放。这样就避免了内存泄漏的问题。
指针语义:使用方式与原始指针相似,可通过指针操作符(->)和解引用操作符(*)来访问所指向对象成员。
禁止拷贝:unique_ptr禁止拷贝,即不能进行复制构造和赋值操作。这是为了确保独占所有权的特性,防止多个指针同时管理同一个对象的内存。
权限转移:支持移动构造和移动赋值操作,将所有权转移给新的unique_ptr而旧指针则自动释放置空,无需进行内存拷贝。
自定义删除器:unique_ptr可通过模板参数来指定一个删除器(deleter)函数对象,用于在释放内存时执行额外的清理操作。
缺点: 使用裸指针赋值或捕获会很容易非常的乱、导致内存泄露,尽量避免智能指针和普通指针的混合。
常见成员函数:
常见成员函数:operator* 解引用操作符,用于获取 unique_ptr 所指向对象的引用。operator-> 箭头操作符,用于通过 unique_ptr 访问对象的成员函数或成员变量。get 返回指向所管理对象的裸指针。reset 重置 unique_ptr,释放当前所管理的对象并接管新的对象。release 释放对所管理对象的控制权,并返回该指针的裸指针。swap 交换两个 unique_ptr 的内容。
示例测试:
基本操作1
#include <iostream>void unique_operate1()
{/******************** 创建 ********************/// 创建方式一,初始化后修改值std::unique_ptr<int> pInt1(new int(10));*pInt1 = 101;// 创建方式二,初始化后修改值std::unique_ptr<int> pInt2 = std::unique_ptr<int>(new int(20));*pInt2 = 102;// 创建方式三,初始化后修改值std::unique_ptr<int> pInt3 = std::make_unique<int>(30);*pInt3 = 103;// 创建多个int指针对象,初始化后修改值std::unique_ptr<int[]> pIntArray(new int[5]{ 10,20,30,40,50 });pIntArray[0] = 1;pIntArray[1] = 2;pIntArray[2] = 3;pIntArray[3] = 4;pIntArray[4] = 5;/*********************************************//******************** 输出地址及值 ********************/std::cout << pInt1 << " " << *pInt1 << " | " << pInt1.get() << " " << *(pInt1.get()) << std::endl;std::cout << pInt1 << " " << *pInt1 << " | " << pInt1.get() << " " << *(pInt1.get()) << std::endl;std::cout << pInt1 << " " << *pInt1 << " | " << pInt1.get() << " " << *(pInt1.get()) << std::endl;/*输出为:000002110F242540 101 | 000002110F242540 101000002110F242540 101 | 000002110F242540 101000002110F242540 101 | 000002110F242540 101*//*********************************************//******************** 权限转移 ********************/std::cout << pInt1 << " " << *pInt1 << std::endl;//std::unique_ptr<int> P1 = pInt1; // 错误操作std::unique_ptr<int> P1 = std::move(pInt1); // 正确操作。此时P1接收了pInt1的地址和值,而pInt1则被置空std::cout << P1 << " " << *P1 << std::endl;/*注意:pInt1由于被置空,此时无法使用否则出现异常。输出为:000002303C431670 101000002303C431670 101*//*********************************************/
}int main()
{// 基本操作1unique_operate1();return 0;
}
基本操作2
#include <iostream>class Operate2
{
public:Operate2(){std::cout << "call Operate2() \t" << this << std::endl;}Operate2(const Operate2 &){std::cout << "call Operate2(const Operate2 &) \t" << this << std::endl;}~Operate2(){std::cout << "call ~Operate2() \t" << this << std::endl;}Operate2* operator +(int v){std::cout << "call operator + \t" << this << std::endl;Operate2 *tmp = new Operate2;tmp->value = value + v;return tmp;}// 设置value值void setValue(const int &v){ value = v; }// 获取value值int getValue()const { return value; }private:int value = 10;
};void unique_operate2()
{// 进入一次Operate2构造(ptr1)std::unique_ptr<Operate2> ptr1 = std::make_unique<Operate2>();/******************** 成员操作 ********************/// 测试std::cout << "print ptr1 ptr add:" << ptr1 << std::endl << std::endl;// 测试 ->std::cout << "print ptr2 - value is:" << ptr1->getValue() << std::endl;ptr1->setValue(20);std::cout << "print ptr2 - value is:" << ptr1->getValue() << std::endl << std::endl;// 测试 get :返回指向所管理对象的裸指针Operate2 *tOperate2Ptr = ptr1.get();std::cout << "tOperate2Ptr - value is:" << ptr1->getValue() << std::endl << std::endl;/*测试 reset :该方法可让unique_ptr解除对原始内存管理,也可初始化一个独占的智能指针reset() 解除对原始内存的管理reset(new xxx()) 重新指定智能指针管理的原始内存*/ptr1.reset(new Operate2()); // 新创建的进入一次构造,然后之前的对象进入一次析构std::cout << "new print ptr2 - value is:" << ptr1->getValue() << std::endl << std::endl;// 测试 release :释放对所管理对象的控制权,并返回该指针的裸指针Operate2 *ttOperate2Ptr = ptr1.release(); // ptr1被置空if (ttOperate2Ptr) { delete ttOperate2Ptr; }ttOperate2Ptr = nullptr;std::cout << std::endl;// 测试 swap :交换两个unique_ptr的内容std::unique_ptr<Operate2> Operate2_1 = std::make_unique<Operate2>(); Operate2_1->setValue(6);std::unique_ptr<Operate2> Operate2_2 = std::make_unique<Operate2>(); Operate2_2->setValue(9);std::cout << "Operate2_1:" << Operate2_1->getValue() << " Operate2_2:" << Operate2_1->getValue() << std::endl;Operate2_1.swap(Operate2_2);std::cout << "Operate2_1:" << Operate2_1->getValue() << " Operate2_2:" << Operate2_1->getValue() << std::endl;/*********************************************/// 函数结束,进入一次Operate2析构(ptr1)
}int main()
{// 基本操作2unique_operate2();/*输出为:call Operate2() 0000029218F50140print ptr1 ptr add:0000029218F50140print ptr2 - value is:10print ptr2 - value is:20tOperate2Ptr - value is:20call Operate2() 0000029218F501C0call ~Operate2() 0000029218F50140new print ptr2 - value is:10call ~Operate2() 0000029218F501C0call Operate2() 0000029218F50140call Operate2() 0000029218F501C0Operate2_1:6 Operate2_2:6Operate2_1:9 Operate2_2:9call ~Operate2() 0000029218F50140call ~Operate2() 0000029218F501C0*/return 0;
}
基本操作3
#include <iostream>class TestClass
{
public:TestClass(){std::cout << "call TestClass() \t" << this << std::endl;}TestClass(const TestClass &){std::cout << "call TestClass(const TestClass &) \t" << this << std::endl;}~TestClass(){std::cout << "call ~TestClass() \t" << this << std::endl;}TestClass* operator +(int v){std::cout << "call TestClass + \t" << this << std::endl;TestClass *tmp = new TestClass;tmp->value = value + v;return tmp;}// 设置value值void setValue(const int &v){ value = v; }// 获取value值int getValue()const { return value; }private:int value = 100;
};std::unique_ptr<TestClass> changeValue_add10(std::unique_ptr<TestClass> tcPtr)
{tcPtr->setValue(tcPtr->getValue() + 10);return tcPtr;
}void unique_operate3()
{std::unique_ptr<TestClass> tcPtr1 = std::make_unique<TestClass>();if (tcPtr1) { std::cout << "11111:\t" << "ptr:" << tcPtr1 << " *ptr:" << tcPtr1->getValue() << std::endl; }//changeValue_add10(stcPtr1); // 错误:由于unique_ptr不能拷贝,故不得作为形参进行拷贝给实参std::unique_ptr<TestClass> tcPtr2 = changeValue_add10(std::move(tcPtr1));if (tcPtr2) { std::cout << "22222:\t" << "ptr:" << tcPtr2 << " *ptr:" << tcPtr2->getValue() << std::endl; }
}int main()
{// 基本操作3unique_operate3();/*输出为:call TestClass() 000001F354580A6011111: ptr:000001F354580A60 *ptr:10022222: ptr:000001F354580A60 *ptr:110call ~TestClass() 000001F354580A60*/return 0;
}
关注
笔者 - jxd