指针创建后忘记删除,或者删除的情况没有考虑清楚,容易造成悬挂指针或者说野指针。
原理RALL:构造的时候分配和创建被管理对象,析构的时候销毁和释放被管理对象,不用担心潜在的内存泄漏
unique_ptr接口:
unique_ptr是对裸指针的封装,存储着一个指针和一个删除器
· 函数对象(函数的指针,仿函数,闭包,std::function)
· 函数对象的左值引用
· 函数的左值引用
unique_ptr在任何给定时刻,只能有一个指针管理内存,当指针超出作用域时,内存将自动释放,该类型指针不可Copy,只可以Move
创建方式:
1. 通过已有的裸指针创建:
#include
#include
using namespace std;
class Student
{
public:
Student() = default;
Student(string name);
~Student();
void Student_info() const;
string Student_get() const;
void Set_name(const string& name);
private:
string name;
};
Student::Student(string name) :name(name)
{
cout << "构造函数已运行" << endl;
}
Student::~Student()
{
cout << "析构函数已运行" << endl;
}
void Student::Student_info() const
{
cout << name << endl;
}
string Student::Student_get() const
{
return name;
}
void Student::Set_name(const string& name)
{
this->name = name;
}
int main() {
Student* s = new Student("张三");
unique_ptr<Student> s1{s};
s->Student_info();
s1->Student_info();
s->Set_name("李四");
s1->Student_info();
return 0;
}
这样无法独占,需要提前delete
Student* s = new Student("张三");
unique_ptr<Student> s1{s};
delete s;
s1->Student_info();
s1->Student_info();
return 0;
2. 通过new来创建:
unique_ptr<Student> s1{new Student("小王")};
s1->Student_info();
s1->Set_name("小李");
s1->Student_info();
return 0;
3. 通过std::make_unique创建(推荐):
unique_ptr<Student> s1 = make_unique<Student>();
s1->Student_info();
s1->Set_name("小李");
s1->Student_info();
return 0;
unique_ptr与函数调用
void get(unique_ptr<Student> s)
{
s->Set_name("小八");
}
int main() {
unique_ptr<Student> s = make_unique<Student>();
s->Set_name("小李");
get(s);//报错无法调用
s->Student_info();
return 0;
}
因为独占的特性,该类型指针不可Copy,所以不能直接调用。
解决方式使用move,但是move将主函数的指针转到了函数中,当函数作用域结束后会自动析构,主函数无法再用这个指针了。
void get(unique_ptr<Student> s)
{
s->Set_name("小八");
s->Student_info();
}
int main() {
unique_ptr<Student> s = make_unique<Student>();
s->Set_name("小李");
get(move(s));
//s->Student_info();报错因为该指针被move了
return 0;
}
由于这个特性所以可以使用引用传值
void get(unique_ptr<Student>& s)
{
s->Set_name("小八");
}
int main() {
unique_ptr<Student> s = make_unique<Student>();
s->Set_name("小李");
s->Student_info();
get(move(s));
s->Student_info();
return 0;
}
shared_ptr:技术指针又称共享指针,与unique_ptr不同它是可以共享数据的
· shared_ptr创建了一个计数器与类对象所指的内存相关联
· Copy则计数器加一,销毁则计数器减一
· api为use_count()
int main() {
shared_ptr<int> i = make_shared<int>(100);
cout << "value : " << i << endl;
cout << "count : " << i.use_count() << endl;
shared_ptr<int> L = i;
cout << "count : " << i.use_count() << endl;
cout << "count : " << L.use_count() << endl;
}
shared_ptr
shared_ptr可以直接复制调用,不用move,但是计数器会加一,直接引用传值不会计数器不会增加,函数运行结束后复制的指针会销毁,所以回到主函数后count会变回原来的数量。
void get(shared_ptr<Student> m, shared_ptr<Student>& n)
{
cout << "copy传值 :" << m.use_count() << endl;
cout << "ref传值 :" << n.use_count() << endl;
}
int main() {
shared_ptr<Student> m = make_shared<Student>();
shared_ptr<Student> n = make_shared<Student>();
m->Set_name("张三");
n->Set_name("李四");
cout << "copy之前 :" << m.use_count() << endl;
cout << "ref之前 :" << n.use_count() << endl;
get(m, n);
cout << "copy之后 :" << m.use_count() << endl;
cout << "ref之后 :" << n.use_count() << endl;
return 0;
}
常见设计:将函数返回值设置为unique_ptr是一种常见的设计模式,这样可以提高代码的复用度,因为unique_ptr可以随时转为 shared_ptr。
int main() {
unique_ptr<Student> m = make_unique<Student>();
shared_ptr<Student> n = make_shared<Student>();
m->Set_name("张三");
n = move(m);
n->Student_info();
cout << n.use_count() << endl;
return 0;
}
weak_ptr用来解决循环依赖的问题