3.智能指针之unique_ptr

匿名 (未验证) 提交于 2019-12-03 00:29:01

3.智能指针之unique_ptr

一、unique_ptrauto_ptr

void fun() {     int *a = new int(1000);     //do something     delete a; }

return

c++unique_ptr

unique_ptr“exclusive ownership”(专属所有权)设计的,专属所有权就是确保了在同一时间一个指针拥有一个对象的全部资源。

unique_ptrp++

void fun() {      unique_ptr<int> a(new int(1000));      //do something  }

unique_ptr

unique_ptr<string>p1 = new string(“string”);//错误 unique_ptr<int>p2(new int(100));

unique_ptr

std::unique_ptr<std::string>p;//p

p = nullptr;p.reset();p

p

我们也可以这样去检测:

release()unique_ptr

std::string *p2 = p.release();//p == nullptr

unique_ptrunique_ptrexclusive ownership

std::string* sp = new std::string("hello"); std::unique_ptr<std::string> up1(sp); std::unique_ptr<std::string> up2(sp);//程序异常。 up1 and up2 own same data

copymove

std::unique_ptr<string> up1(new string); std::unique_ptr<string> up2(up1); //错误,无法通过编译 std::unique_ptr<string> up3(std::move(up1));//ok,move语义

std::unique_ptr<string> up1(new string); std::unique_ptr<string> up2; // create another unique_ptr up2 = up1; // ERROR: not possible up2 = std::move(up1);

看下面这几行代码:

std::unique_ptr<ClassA> up1(new ClassA); std::unique_ptr<ClassA> up2(new ClassA); up2 = std::move(up1);

up2moveup2up2delete

unique_ptrunique_ptr

ptr = new ClassA; // ERROR ptr = std::unique_ptr<ClassA>(new ClassA); // OK, delete old object

ptrnullptr

ptr = nullptr;//ptr.reset();

move

unique_ptr

void fun(unique_ptr<string>str) { 	cout << *str; } ... unique_ptr<string>str(new string("hello world")); fun(unique_ptr<string>(new string ("test"))); fun(std::move(str)); ...

:fun(unique_ptr<string>str)

unique_ptr

unique_ptr<string, void(*)(string*)>fun() { 	unique_ptr < string, void(*)(string*) > str(new string("1111"), [](string *str) 	{ 		cout << *str; 		delete str; 	}); 	return str; } ... auto it = fun(); ...

move(),C++11move

二、unique_ptr


class ClassB { private: 	ClassA* ptr1; // pointer members 	ClassA* ptr2; public: 	// constructor that initializes the pointers 	// - will cause resource leak if second new throws 	ClassB(int val1, int val2) 		: ptr1(new ClassA(val1)), ptr2(new ClassA(val2)) { 	} 	// copy constructor 	// - might cause resource leak if second new throws 	ClassB(const ClassB& x) 		: ptr1(new ClassA(*x.ptr1)), ptr2(new ClassA(*x.ptr2)) { 	} 	// assignment operator 	const ClassB& operator= (const ClassB& x) { 		*ptr1 = *x.ptr1; 		*ptr2 = *x.ptr2; 		return *this; 	} 	~ClassB() { 		delete ptr1; 		delete ptr2; 	} 	... };

ptr2时抛出一个异常,那么将会造成ptr1的内存泄漏,为了避免该问题的发生,我们可以将代码中的普通指针更改为unique_ptr。

class ClassB { private: std::unique_ptr<ClassA> ptr1; // unique_ptr members std::unique_ptr<ClassA> ptr2; public: // constructor that initializes the unique_ptrs // - no resource leak possible ClassB (int val1, int val2) : ptr1(new ClassA(val1)), ptr2(new ClassA(val2)) { } // copy constructor // - no resource leak possible ClassB (const ClassB& x) : ptr1(new ClassA(*x.ptr1)), ptr2(new ClassA(*x.ptr2)) { } // assignment operator const ClassB& operator= (const ClassB& x) { *ptr1 = *x.ptr1; *ptr2 = *x.ptr2; return *this; } // no destructor necessary // (default destructor lets ptr1 and ptr2 delete their objects) ... };

ClassA也需要实现copy 构造函数以及赋值操作,否则将只会调用move构造函数

三、操作数组
std::unique_ptr<std::string> up(new std::string[10]); // runtime ERROR

unique_ptr与shared_ptr有所区别,我们可以直接声明为

std::unique_ptr<std::string[]> up1(new std::string[10]);//ok std::cout << *up << std::endl; // ERROR: * not defined for arrays std::cout << up[0] << std::endl; // OK,此时我们应该确保下标不能越界

unique_ptr内部中关于使用数组声明以及普通参数的区别。

namespace std { // primary template: template <typename T, typename D = default_delete<T>> class unique_ptr { public: ... T& operator*() const; T* operator->() const noexcept; ... }; // partial specialization for arrays: template<typename T, typename D> class unique_ptr<T[], D> { public: ... T& operator[](size_t i) const; ... } }

default_delete

namespace std { // primary template: template <typename T> class default_delete { public: void operator()(T* p) const; // calls delete p ... }; // partial specialization for arrays: template <typename T> class default_delete<T[]> { public: void operator()(T* p) const; // calls delete[] p ... }; }

std::unique_ptr<std::string> up1(new std::string[10]);//error std::unique_ptr<std::string[]> up1(new std::string[10]);//ok

四、

default_delete 与 default_delete[]无法满足我们的要求,此时我们需要定义我们自己的删除器,而我们在这里定义的删除器与在shared_ptr中的定义方式又有一些不同,在unique_ptr中我们必须将删除器的类型,作为模板的第二个参数声明,这个参数可以是函数引用,函数指针或者一个函数对象。

class ClassADeleter 	{ 	public: 		void operator () (ClassA* p) { 			std::cout << "call delete for ClassA object" << std::endl; 			delete p; 		} 	};... std::unique_ptr<ClassA,ClassADeleter> up(new ClassA());

lambda表达式,但是也需要声明这个函数的类型,例如:

std::unique_ptr<int,void(*)(int*)> up(new int[10], [](int* p) { ... delete[] p; });

或者

auto dl = [](int* p) { ... delete[] p; }; std::unique_ptr<int,decltype(dl)>> up(new int[10], dl);

template <typename T> 	using uniquePtr = std::unique_ptr<T, void(*)(T*)>; // alias template 	... 		uniquePtr<int> up(new int[10], [](int* p) { // used here 		... 			delete[] p; 	});

注意:

unique_ptr<int>p1(new int);       //OK unique_ptr<int>p2(new int[10]);   //error可以编译但是程序会崩溃 unique_ptr<int[]>p3(new int[10]); /OK shared_ptr<int>p4(new int);       //OK shared_ptr<int>p5(new int[10]);   //可以通过编译但会崩溃 shared_ptr<int[]>p6(new int[10]); //无法通过编译

unique_ptr中允许将类型声明为void的,所以void*也是可以的

T被声明为T[]时,[]操作将会代替*和->

delete[]和delete两种



易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!