C++ —— 智能指针 unique_ptr (上)
普通指针的不足
new
和new []
的内存需要用delete
和delete []
释放(堆区的内存一定要手工释放,否则会发生内存的泄露);- 程序员主观上的失误,忘记或漏掉释放;
- 不确定何时释放。
普通指针的释放
类内
的指针
,在析构函数
中释放
;- 堆区的内存是
C++
内置数据类型,没有析构函数,只能delete
释放; new
出来的类,还是得用delete
释放。
智能指针
智能指针
的目的:解决资源释放的问题。
智能指针使用步骤:
- 智能指针是类模板,在栈上创建智能指针对象;
- 把普通指针交给智能指针对象;
- 智能指针对象过期时,调用析构函数释放普通指针的内存。
C++11
标准的智能指针类型:unique_ptr
、shared_ptr
、weak_ptr
。
智能指针 unique_ptr
C++
中,多个
指针可以指向同一个
对象。
unique_ptr 独享
它指向的对象,也就是说,同时只
有一
个unique_ptr
指向同一个对象,当这个unique_ptr
被销毁
时,指向
的对象
也随即被销毁
。
示例代码如下:
#include <iostream>
#include <memory> // 使用智能指针需要包含的头文件
using namespace std;
class A {
public:
string m_name;
A() {cout << "A()" << endl;}
A(const string& name): m_name(name) {cout << "A(const string&)" << endl;}
~A() {cout << "~A()" << endl;}
};
int main () {
A* pa = new A("aaa");
// delete pa;
return 0;
}
因为没有delete
,所以只有构造函数的日志信息,运行结果如下:
A(const string&)
使用智能指针unique_ptr
来管理普通指针pa
代码如下:
int main () {
A* pa = new A("aaa");
unique_ptr<A> pu_a(pa); // 间接地让智能指针 pu_a 来管理对象
// 需要管理的普通指针的基类型是 A(也就是模板参数)
// pa 是被管理的指针,pa 指向了 new 出来的对象的地址。
return 0;
}
运行效果如下:
A(const string&)
~A()
可以看到,尽管没有使用delete
语句,也销毁了A
的对象。原因是:智能指针
是类
,它有析构函数
,在它的析构函数中,使用了delete
语句。
可以像使用普通指针一样去使用智能指针,代码如下:
int main () {
A* pa = new A("aaa");
// delete pa;
unique_ptr<A> pu_a(pa);
cout <<"m_name = " << (*pa).m_name << endl;
cout << "m_name = " << pa->m_name << endl;
cout << "m_name = " << (*pu_a).m_name << endl;
cout << "m_name = " << pu_a->m_name << endl;
return 0;
}
运行效果如下:
A(const string&)
m_name = aaa
m_name = aaa
m_name = aaa
m_name = aaa
~A()
智能指针初始化
- 方法一(常用):
unique_ptr<A> pu_a(new A("abcd")); // 分配内存并初始化
int main () {
unique_ptr<A> pu_a(new A("abcd"));
// new 返回的是对象的地址
cout <<"m_name = " << (*pu_a).m_name << endl;
cout << "m_name = " << pu_a->m_name << endl;
return 0;
}
运行效果如下:
A(const string&)
m_name = abcd
m_name = abcd
~A()
- 方法二:
unique_ptr<A> p = make_unique<A>("abcd"); // C++14标准
unique_ptr<int> p1=make_unique<int>(); // 数据类型为int
unique_ptr<A> p2 = make_unique<A>(); // 数据类型为A,默认构造函数
unique_ptr<A> p3 = make_unique<A>("abcd"); // 数据类型为A,一个参数的构造函数
unique_ptr<A> p4 = make_unique<A>("abcd","efgh"); // 数据类型为A,两个参数的构造函数
- 方法三(不推荐):
A* p = new A("abcd");
unique_ptr<A> pu (p); // 用已存在的地址初始化
错误用法
A* p = new a("abcd");
unique_ptr<A> pu1 = p; // 错误,不能把普通指针直接赋给智能指针。
unique_ptr<A> pu2 = new A("abcd"); // 错误,不能把普通指针直接赋给智能指针。
unique_ptr<A> pu3 = pu2; // 错误,不能用其它unique_ptr拷贝构造。
unique_ptr<A> pu4;
pu4 = pu1; // 错误,不能用 = 对 unique_ptr 进行赋值。
// 裸指针就是普通指针 pa就是普通指针,也叫裸指针
A* pa = new A("efgh");
unique_ptr<A> pu_a1(pa);
unique_ptr<A> pu_a2(pa);
unique_ptr<A> pu_a3(pa);
// 程序会异常退出,原因是:多个unique_ptr对象对同一块内存释放了多次
get()方法返回裸指针
int main () {
A* pa = new A("efgh");
unique_ptr<A> pu_a(pa);
cout << "裸指针的值是:" << pa << endl;
cout << "pu_a.get() = " << pu_a.get() << endl;
// cout << pa->m_name << endl; // efgh
// cout << pu_a.get()->m_name << endl; // efgh
cout << "pu_a的地址:" << &pu_a << endl;
// pu_a是unique_ptr<A>模板类创建的对象,有自己的地址。
// 自己的地址和它管理的原始指针的地址不是一回事
return 0;
}
运行结果如下:
A(const string&)
裸指针的值是:0x557320cf6eb0
pu_a.get() = 0x557320cf6eb0
pu_a的地址:0x7ffde063e680
~A()
智能指针不支持指针的运算(+、-、++、- -)
感谢浏览,一起学习!