cpp_smart_pointer - ShenYj/ShenYj.github.io GitHub Wiki
传统指针存在的问题
- 需要手动管理内存
- 容易发生内存泄露(忘记释放、出现异常等)
- 释放之后产生野指针
智能指针就是为了解决传统指针存在的问题
-
auto_ptr
:属于C++98标准,在C++11中已经不推荐使用(有缺陷,比如不能用于数组) -
shared_ptr
:属于C++11标准 -
unique_ptr
:属于C++11标准
class Person {
public:
int m_age;
Person(int age) :m_age(age) {
cout << "Person()" << endl;
}
~Person() {
cout << "~Person()" << endl;
}
void run() { }
};
int main() {
/// 常规写法
Person *p1 = new Person(10);
/// 保证指针p使用完后释放
delete p1;
/// 利用`auto_ptr`智能指针, 注意没有 *
/// 智能指针p 指向了堆空间的 Person 对象
/// 不用像传统指针一样去管 delete
/// 智能指针所指向的对象生命周期跟随智能指针,也就是智能指针被销毁了,对象也就随之释放内存
auto_ptr<Person> p(new Person(20));
p->run();
}
使用智能指针不要指向栈空间对象, 而是要指向堆空间对象
/// 这种写法会出现多次析构
Person person(20); /// 栈空间
auto_ptr<Person> p(&person);
template <class T>
class SmartPointer {
T *m_pointer;
public:
SmartPointer(T *pointer) :m_pointer(pointer) { }
~SmartPointer() {
if (m_pointer == nullptr) return;
delete m_pointer;
}
T *operator->() {
return m_pointer;
}
};
SmartPointer<Person> p(new Person(20));
p->run();
-
多个shared_ptr可以指向同一个对象,当最后一个shared_ptr在作用域范围内结束时,对象才会被自动释放
/// p1 p2 p3 p4 四个智能指针都指向了堆区那个 Person 对象 shared_ptr<Person> p1(new Person(10)); shared_ptr<Person> p2 = p1; shared_ptr<Person> p3 = p1; shared_ptr<Person> p4(p3);
-
可以通过一个已存在的智能指针初始化一个新的智能指针
shared_ptr<Person> p1(new Person()); shared_ptr<Person> p2(p1);
-
针对数组的用法
shared_ptr<Person[]> persons(new Person[5]{}); /// 不推荐,既然使用了智能指针,就没必要再考虑delete了 shared_ptr<Person> ptr1(new Person[5]{}, [](Person *p) { delete[] p; });
- 一个shared_ptr会对一个对象产生强引用(strong reference)
- 每个对象都有个与之对应的强引用计数,记录着当前对象被多少个shared_ptr强引用着
- 可以通过shared_ptr的use_count函数获得强引用计数
- 当有一个新的shared_ptr指向对象时,对象的强引用计数就会+1
- 当有一个shared_ptr销毁时(比如作用域结束),对象的强引用计数就会-1
- 当一个对象的强引用计数为0时(没有任何shared_ptr指向对象时),对象就会自动销毁(析构)
/// 打印有多少个 shared_ptr 智能指针强引用着对象
/// 将p1 换成 p2 p3 p4 打印结果一样,因为指向的是同一个对象
shared_ptr<Person> p1(new Person(10));
cout << p1.user_count() << endl; // 1
shared_ptr<Person> p2 = p1;
cout << p1.user_count() << endl; // 2
shared_ptr<Person> p3 = p1;
cout << p1.user_count() << endl; // 3
shared_ptr<Person> p4(p3);
cout << p1.user_count() << endl; // 4
Person *p = new Person(); // Person()
{
shared_ptr<Person> p1(p);
} // ~Person()
{
shared_ptr<Person> p2(p);
} // ~Person()
上面这段代码的问题是: 一次构造,因为作用域的原因产生了两次析构
循环引用主要是针对智能指针,如果使用传统指针,都是手动管理内存
使用 weak_ptr
解决循环引用
-
weak_ptr
会对一个对象产生弱引用 -
weak_ptr
可以指向对象解决shared_ptr
的循环引用问题class Car { public: weak_ptr<Person> m_person; }; class Person { public: shared_ptr<Car> m_car = nullptr; }; int main() { shared_ptr<Person> person(new Person()); shared_ptr<Car> car(new Car()); person->m_car = car; car->m_person = person; return 0; }
-
unique_ptr
也会对一个对象产生强引用,它可以确保同一时间只有1个指针指向对象 - 当
unique_ptr
销毁时(作用域结束时),其指向的对象也就自动销毁了 - 可以使用
std::move
函数转移unique_ptr
的所有权
/// ptr1强引用着person对象
unique_ptr<Person> ptr1(new Person());
/// 转移之后, ptr2 强引用着person对象
unique_ptr<Person> ptr2 = std::move(ptr1);