C++智能指针unique_ptr 详解

一、智能指针

在C++中,动态内存的使用很容易出问题,因为要确保在正确的时间释放内存是极其困难的。有时会忘记释放内存,在这种情况下会产生内存泄露;有时在尚有指针引用内存的情况下就释放了它,在这种情况下就会产生引用非法内存的指针。

C++智能指针是包含重载运算符的类,其行为像常规指针,但智能指针能够及时、妥善地销毁动态分配的数据,并实现了明确的对象生命周期,因此更有价值。

二、unique_ptr 简介

unique_ptr 是从 C++ 11 开始,定义在 <memory> 中的智能指针(smart pointer)。它持有对对象的独有权,即两个 unique_ptr 不能指向一个对象,不能进行复制操作只能进行移动操作。

unique_ptr 之所以叫这个名字,是因为它智能指向一个对象,即当它指向其他对象时,之前所指向的对象会被摧毁。其次,当 unique_ptr 超出作用域时,指向的对象也会被自动摧毁。

std::unique_ptr<int>p1(new int(5));
	std::unique_ptr<int>p2 = p1;// 编译会出错
	std::unique_ptr<int>p3 = std::move(p1);// 转移所有权, 现在那块内存归p3所有, p1成为无效的针.
	p3.reset();//释放内存.
	p1.reset();//无效

三、常用方法

1 构造方法 std::unique_ptr::unique_ptr

// unique_ptr constructor example
#include <iostream>
#include <memory>
 
int main () {
  std::default_delete<int> d;
  std::unique_ptr<int> u1;
  std::unique_ptr<int> u2 (nullptr);
  std::unique_ptr<int> u3 (new int);
  std::unique_ptr<int> u4 (new int, d);
  std::unique_ptr<int> u5 (new int, std::default_delete<int>());
  std::unique_ptr<int> u6 (std::move(u5));
  std::unique_ptr<int> u7 (std::move(u6));
  std::unique_ptr<int> u8 (std::auto_ptr<int>(new int));
 
  std::cout << "u1: " << (u1?"not null":"null") << '\n';
  std::cout << "u2: " << (u2?"not null":"null") << '\n';
  std::cout << "u3: " << (u3?"not null":"null") << '\n';
  std::cout << "u4: " << (u4?"not null":"null") << '\n';
  std::cout << "u5: " << (u5?"not null":"null") << '\n';
  std::cout << "u6: " << (u6?"not null":"null") << '\n';
  std::cout << "u7: " << (u7?"not null":"null") << '\n';
  std::cout << "u8: " << (u8?"not null":"null") << '\n';
 
  return 0;
}

2、释放方法 std::unique_ptr::release

这里的释放并不是摧毁(destory)其指向的对象,而是将其指向的对象释放(release)出去,即转移该对象到另一个指针那里去。使用release 会切断unique_ptr 和它原来管理的对象的联系。release 返回的指针通常被用来初始化另一个智能指针或给另一个智能指针赋值。如果不用另一个智能指针来保存release返回的指针,程序就要负责资源的释放。

比如这个例子,auto_poiner执行release方法后,它就会变成一个nullptr,但是它把指向的对象转移到manual_pointer中了。

int main()
{

	std::unique_ptr<int> auto_pointer(new int);
	int * manual_pointer;
	*auto_pointer = 10;
	manual_pointer = auto_pointer.release();
	// (auto_pointer is now empty)
	std::cout << "manual_pointer points to " << *manual_pointer << '\n';

	std::cout << "auto_pointer points to " << (auto_pointer ? "not null" : "nullptr") << '\n';

	delete manual_pointer;
        return 0;
}

 

 另一个例子

  unique_ptr<Foo> temp = get_me_some_foo();  // manages the object
  Foo * ptr = temp.release();        // pointer to no-longer-managed object
  temp.get_deleter() ( ptr );

3、重置方法 std::unique_ptr::reset

先将up所指对象释放,然后重置up的值

// unique_ptr::reset example
#include <iostream>
#include <memory>
 
int main () {
	std::unique_ptr<int> up;  // empty
	up.reset(new int);       // takes ownership of pointer
	*up = 5;
	std::cout << *up << '\n';
	up.reset(new int);       // deletes managed object, acquires new pointer
	*up = 10;
	std::cout << *up << '\n';
	up.reset();               // deletes managed object

	std::cout << "up to " << (up ? "not null" : "nullptr") << '\n';
        return 0;
}

 

4、交换方法 std::unique_ptr::swap

// unique_ptr::swap example
#include <iostream>
#include <memory>
 
int main () {
  std::unique_ptr<int> foo (new int(10));
  std::unique_ptr<int> bar (new int(20));
  foo.swap(bar);
  std::cout << "foo: " << *foo << '\n';
  std::cout << "bar: " << *bar << '\n';
  return 0;
}

5、自定义资源删除操作(Deleter)

// unique_ptr destructor example
#include <iostream>
#include <memory>
 
int main () {
  // user-defined deleter
  auto deleter = [](int*p){
    delete p;
    std::cout << "[deleter called]\n";
  };
  std::unique_ptr<int,decltype(deleter)> foo (new int,deleter);
  std::cout << "foo " << (foo?"is not":"is") << " empty\n";
  return 0; // [deleter called]
}

四、unique_ptr的陷阱 

unique_ptr不允许两个独占指针指向同一个对象,在没有裸指针的情况下,我们只能用release获取内存的地址,同时放弃对对象的所有权,这样就有效避免了多个独占指针同时指向一个对象。 
而使用裸指针就很容器打破这一点

int main()
{	
     
	int *x(new int(2));
	unique_ptr<int> up1, up2;
	//会使up1 up2指向同一个内存
	up1.reset(x);
	std::cout << "x to " << (x ? "not null" : "nullptr") << '\n';
	std::cout << *x << '\n';
	up2.reset(x);
	std::cout << "x to " << (x ? "not null" : "nullptr") << '\n';
	*up1 = 5;
	std::cout << *up1 << '\n';
	std::cout << *up2 << '\n';

	std::cout << "x to " << (x ? "not null" : "nullptr") << '\n';
	std::cout << *x << '\n';
}

另一个例子

int main()
{

	int* p = nullptr;                        // null  null  null
	p = std::unique_ptr<int>(new int(5)).get();
	std::cout << "p to " << (p ? "not null" : "nullptr") << '\n';
	std::cout << *p << '\n';
}

所以,尽量避免智能指针和普通指针的混合,那样容易非常的乱,导致内存泄露,程序崩溃 

参考:

https://blog.csdn.net/afei__/article/details/80670283

https://blog.csdn.net/qq_33266987/article/details/78784286

猜你喜欢

转载自blog.csdn.net/sinat_31608641/article/details/107677241