std::unique_ptr<>
使用它需要包含头文件。
unique_ptr
对象可以用于维护普通(常常用于索引一块内存)的指针,在其生命周期结束后,自动地删除它,并释放相关的内存。unique_ptr
重载了->和*运算符,因此可以像使用普通指针那样使用 unique_ptr 智能指针。
1. 特点:“专享所有权”
保证同一时间内只有一个智能指针可以指向该对象。
unique_ptr<string> p3 (new string ("auto")); //#4
unique_ptr<string> p4; //#5
p4 = p3;//此时会报错!!
编译器认为p4=p3非法,避免了p3不再指向有效数据的问题。尝试复制p3时会编译期出错,而auto_ptr能通过编译期从而在运行期埋下出错的隐患。因此,unique_ptr比auto_ptr更安全。
如果想转移指针的所有权,C++有一个标准库函数std::move()实现。
可以通过release()方法,释放所有权。
例子:
#include <iostream>
#include <memory>
using namespace std;
struct Task
{
int mId;
Task(int id):mId(id)
{
std::cout<<"调用构造函数"<<mId <<endl;
}
~Task()
{
std::cout<<"调用析构函数"<<mId <<endl;
}
};
int main()
{
std::unique_ptr<Task> myTaskPtr1(new Task(11));
std::cout<<"id="<<myTaskPtr1->mId<<endl;
return 0;
}
编译执行:
$ g++ -g main.cpp -std=c++11
$ ./a.out
结果:
调用构造函数11
id=11
调用析构函数11
2. 不能直接赋值:
[liqzh@rbtnode1 test02]$ cat main.h
#include <iostream>
#include <memory>
using namespace std;
struct Task
{
int mId;
Task(int id):mId(id)
{
std::cout<<"调用构造函数"<<mId <<endl;
}
~Task()
{
std::cout<<"调用析构函数"<<mId <<endl;
}
};
int main()
{
std::unique_ptr<Task> myTaskPtr1(new Task(11));
std::unique_ptr<Task> myTaskPtr2 = myTaskPtr1;
std::cout<<"id="<<myTaskPtr1->mId<<endl;
return 0;
}
这种情况下,会出现编译错误:
[liqzh@rbtnode1 test02]$ g++ -g main2.cpp -o main2 -std=c++11
main2.cpp: 在函数‘int main()’中:
main2.cpp:9:40: 错误:使用了被删除的函数‘std::unique_ptr<_Tp, _Dp>::unique_ptr(const std::unique_ptr<_Tp, _Dp>&) [with _Tp = Task; _Dp = std::default_delete<Task>]’
std::unique_ptr<Task> myTaskPtr2 = myTaskPtr1;
需要使用std::move,来转移所有权:
#include "main.h"
int main()
{
std::unique_ptr<Task> myTaskPtr1(new Task(11));
if(!myTaskPtr1)
std::cout<<"myTaskPtr1 is empty"<<std::endl;
else
std::cout<<"myTaskPtr1 is not empty"<<std::endl;
std::unique_ptr<Task> myTaskPtr2 = std::move(myTaskPtr1);
if(!myTaskPtr1)
std::cout<<"myTaskPtr1 is empty"<<std::endl;
else
std::cout<<"myTaskPtr1 is not empty"<<std::endl;
if(!myTaskPtr2)
std::cout<<"myTaskPtr2 is empty"<<std::endl;
else
std::cout<<"myTaskPtr2 is not empty"<<std::endl;
std::cout<<"id="<<myTaskPtr2->mId<<endl;
return 0;
}
结果:
[liqzh@rbtnode1 test02]$ g++ -g main3.cpp -o main3 -std=c++11
[liqzh@rbtnode1 test02]$ ./main3
调用构造函数11
myTaskPtr1 is not empty
myTaskPtr1 is empty
myTaskPtr2 is not empty
id=11
调用析构函数11
也可以调用release()方法,释放所有权给普通指针:
#include "main.h"
int main()
{
std::unique_ptr<Task> myTaskPtr2(new Task(11));
Task *ptr = myTaskPtr2.release();
if(!myTaskPtr2)
std::cout<<"myTaskPtr2 is empty"<<std::endl;
else
std::cout<<"myTaskPtr2 is not empty"<<std::endl;
std::cout<<"id="<<ptr->mId<<endl;
delete ptr;
return 0;
}
结果:
[liqzh@rbtnode1 test02]$ g++ -g main4.cpp -o main4 -std=c++11
[liqzh@rbtnode1 test02]$ ./main4
调用构造函数11
myTaskPtr2 is empty
id=11
调用析构函数11
[liqzh@rbtnode1 test02]$
另外,unique_ptr还有个reset()方法:
// 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
return 0;
}
结果:
[liqzh@rbtnode1 test02]$ g++ -g main5.cpp -o main5 -std=c++11
[liqzh@rbtnode1 test02]$ ./main5
5
10