C++智能指针unique

C++11:unique_ptr、shared_ptr、weak_ptr,本节介绍一下unique_ptr

1.智能指针产生原因

众所周知,C++程序设计中使用堆内存是非常频繁的操作,堆内存的申请和释放都由程序员自己管理。然而,很多程序员在使用堆内存时都很头疼,因为一次不恰当的使用方法,很容易造成堆内存泄露(忘记释放),二次释放,程序发生异常时内存泄露等问题等。所以C++引入了智能指针,使用使用智能指针能更好的管理堆内存。

2.理解智能指针原理

1)智能指针是利用了一种叫做RAII技术对普通的指针进行封装,这使得智能指针实质是一个对象,行为表现的却像一个指针。

补充:RAII技术即资源分配及初始化,使用类来封装资源的分配和初始化,构造函数完成资源的分配和初始化,析构函数完成资源的清理,可以保证正确的初始化和资源释放。

2)智能指针是一个类,这个类的构造函数中传入一个普通指针,析构函数中释放传入的指针。智能指针的类都是栈上的对象,所以当函数(或程序)结束时会自动被释放。智能指针的作用是防止忘记调用delete释放内存和程序异常的进入catch块忘记释放内存。另外指针的释放时机也是非常有考究的,多次释放同一个指针会造成程序崩溃,这些都可以通过智能指针来解决。千万不要用一块非new分配的动态内存去初始化一个智能指针,因为自行释放非堆地址很有可能出现问题。

3)智能指针还有一个作用是把值语义转换成引用语义。

C++和Java有一处最大的区别在于语义不同,在Java里面,下列代码: 

Student s1 = new Student ();

Student s2 = s1;

 这里其实只生成了一个对象,s1和s2仅仅是共享对象的引用而已。但在C++中不是这样的,

  Student s1;

  Student s2 = s1;

  这里却是就是生成了两个对象。

3.包含头文件

C++98版的auto_ptr和C++11版的unique_ptr、shared_ptr、weak_ptr,都包含在头文件memory中,隶属于std命名空间中。

4.unique_ptr

unique_ptr持有对对象的独有权——两个unique_ptr不能指向一个对象,不能进行复制操作只能进行移动操作。但支持通过std::move转移内部指针所有权。

unique_ptr的成员函数:

1)get 获得内部对象的指针, 由于已经重载了()方法, 因此和直接使用对象是一样的.如 unique_ptrint sp(new int(1)); sp 与 sp.get()是等价的;
2)release 放弃内部对象的所有权,将内部指针置为空, 返回所内部对象的指针, 此指针需要手动释放;
3)reset 销毁内部对象并接受新的对象的所有权(如果使用缺省参数的话,也就是没有任何对象的所有权, 此时仅将内部对象释放, 并置为空);

unique_ptrint up1(new int);	// ok
up1 = nullptr;	//显式销毁所指对象,同时智能指针变为空指针。与u_s2.reset()等价

4)swap 交换两个unique_ptr对象(即交换所拥有的对象);

unique_ptr的用法:

1)unique_ptr对象不能进行拷贝和赋值操作,只能进行移动操作

unique_ptrint up1(new int);		// ok
unique_ptrint up2 = up1;		// 编译错误
unique_ptrint up3(up1);		// 编译错误
unique_ptrint up4 = move(up1);	// ok,up1变成空指针

查看拷贝构造和赋值源码,可以看到它们都被标记为已删除的函数了,在编译上面的代码时,会报编译错误:

unique_ptr(const _Myt) = delete;
_Myt operator=(const _Myt) = delete;

当然,有些博主解释为,它们被设成了不可访问的私有函数。 

虽然 unique_ptr 不支持拷贝和赋值, 但是可以调用 release 或 reset 将指针的所有权从一个(非 const) unique_ptr 转移到另一个。

std::unique_ptrint up1(new int(1));
std::unique_ptrint up2(up1.release()); // up1 放弃内部对象的所有权,将内部指针置为空
std::unique_ptrint up3(new int(2));
up3.reset(up2.release());	//up3销毁内部对象,并接受新的对象的所有权

2)源unique_ptr是临时右值时,编译器允许将源unique_ptr临时右值赋给另一个unique_ptr对象

// 可以进行移动构造
template class Ty
std::unique_ptrTy Clone(const Ty obj)
{
	std::unique_ptrTy temp = std::unique_ptrTy(new Ty(obj)); // 编译器允许,源右值对象是临时右值
	return temp;	// 对象的所有权被传递出Clone()
}

unique_ptrint pu1 = Clone(5);// 可以进行移动赋值,Clone函数返回值也是临时右值
unique_ptrint pu2;
pu2 = pu1;                          // pu1不是临时右值,编译器不允许
unique_ptrint pu3;
pu3 = unique_ptrint(new int(2));  // 编译器允许,源右值对象是临右值

应该是编译器知道要临时右值的unique_ptr对象即将被销毁, 因此执行一种特殊的"拷贝"。

3)两个unique_ptr不能指向一个对象

int *iPtr = new int(0);
std::unique_ptrint up1(iPtr);
std::unique_ptrint up2(iPtr);// 编译可以通过,但运行时发生错误

up2和up1都指向了iPtr,将来iPtr会被释放两次,造成错误。

4)unique_ptr支持管理动态数组

因为unique_ptr有unique_ptrX[]重载版本,销毁动态对象时调用delete[]

unique_ptrint[] p (new int[3]{1,2,3});  
p[0] = 0;// 重载了operator[]

5)可以使用unique_ptr的移动语义将对象插入容器中

unique_ptrint pu1(new int(1));
vectorunique_ptrint  vect;
vect.push_back(pu1);			// 编译错误
vect.push_back(std::move(pu1));	// OK,使用移动语义,pu1自己就不把持对象所有权了

 

最新回复(0)
/jishuGBj530XYqfZRKLba0fz2G6yNrgYQY1G0vJI7cw_3D_3D4858743
8 简首页