C++ 4种智能指针的定义与使用——学习记录008

1.智能指针

1.1作用

智能管理动态分配的内存,自动释放程序员new出来的内存,从而避免内存泄漏。

1.2原理

动态分配的内存交给有生命周期的对象处理,在对象过期时,内存的释放交给对象来处理。

1.3使用方法

#include
auto_ptr<类型> 变量名称(new 类型);

auto_ptr str(new string("string型智能指针测试"));
auto_ptr> v(new vecotr);
auto_ptr array(new int[10]);

智能指针内部实现了*,->运算符重载,可以像普通指针一样使用。

1.4常用函数

1) get()函数:获取指针返回

auto_ptr test(new Test);

Test *tmp = test.get();        // 获取指针返回

2) release()函数:取消智能指针对动态内存的托管,会将内存的地址返回

auto_ptr test(new Test);
Test *tmp = test.release();        // 取消智能指针对动态内存的托管
delete tmp;            // 手动释放

3) reset()函数:释放智能指针托管的指针内存

autp_ptr test(new Test);
test.reset();                 // 释放智能指针托管的指针内存,将其置为NULL
test.reset(new Test());       // 释放智能指针托管的指针内存,并指向形式参数中的内存地址

存在的问题:

1.复制或者赋值都会改变资源的所有权

2.在STL容器中使用auto_ptr存在风险,因为容器中元素必须可复制和可赋值

3.不支持对象数组管理

1)复制和赋值的资源所有权问题

// auto_ptr 被C++11抛弃的主要原因
auto_ptr p1(new string("I'm Li Ming!"));
auto_ptr p2(new string("I'm age 22."));

cout << "p1:" << p1.get() << endl;
cout << "p2:" << p2.get() << endl;

/*
 TODO p2赋值给p1后,首先p1会先将自己原先托管的内存释放掉,然后接收托管p2所托管的内存,
 然后p2所托管的指针为NULL,也就是p1托管了p2托管的内存,而p2放弃了托管。
 */ 
p1 = p2;    
cout << "p1 = p2 赋值后:" << endl;
        // 结构托管
cout << "p1:" << p1.get() << endl;        // 输出p1托管的地址
cout << "p2:" << p2.get() << endl;
        // 输出为null空地址
cout << *p2.get() << endl;                 // 出错——空地址取值运算

2)STL容器中使用auto_ptr的风险,首先需要对auto_ptr进行move修饰

vector> vec;
auto_ptr p3(new string("I'm P3"));
auto_ptr p4(new string("I'm P4"));

// 必须使用std::move修饰成右值,才可以进行插入到容器中
vec.push_back(std::move(p3));
vec.push_back(std::move(p4));

cout << "vec.at(0):" <<  *vec.at(0) << endl;
cout << "vec[1]:" <<  *vec[1] << endl;


// 出错
// 在这里进行赋值,赋值成功后,vec[1]智能指针将被释放,输出将会出错
vec[0] = vec[1];    // 如果进行赋值,问题又回到了上面一个问题中。
cout << "vec.at(0):" << *vec.at(0) << endl;
cout << "vec[1]:" << *vec[1] << endl;

3)不支持对象数组管理

auto_ptr array(new int[5]);    // 出错

2. C++11 智能指针新特性

1. unique_ptr独占对象所有权,没有使用引用计数,整体性能良好

2. shared_ptr共享对象的所有权,使用引用计数,性能较差

3. weak_ptr配合shared_ptr,解决循环引用问题

unique_ptr指针替换了auto_ptr智能指针,特性:

1.基于排他所有权模式,两个指针不能指向同一个资源。

2.无法进行左值unique_ptr赋值构造,也无法进行左值复制赋值操作,但允许临时右赋值和构造赋值。

3.在容器中保存指针是安全的

4.unique_ptr可以指向一个数组

5.unique_ptr需要指定删除器的类型

shared_ptr特性

使用引用计数,每一个shared_ptr的拷贝都指向相同的内存,在最后一个shared_ptr析构时,被托管的内存才会释放。

shared_ptr共享管理的对象,同一时刻可以有多个shared_ptr拥有对象的所有权。

shared_ptr 的小问题:当有两个对象中成员变量都使用了一个shared_ptr指针,并将shared_ptr指针都指向了对方,会造成循环引用,使引用计数失效,从而导致内存泄漏。

/*
    1. 不能使用原始指针初始化多个shared_ptr
    2. 函数实参中不要创建shared_ptr指针       // 因为函数参数的计算顺序不一定每次相同,先定义后使用
    3. 不要通过shared_from_this()返回this指针    // 可能导致重复析构
*/

       int *ptr = new int;
    shared_ptr p1(ptr);
    shared_ptr p2(ptr);    // 出错

    /// 可能顺序:先new一个int,然后去调用g()函数,shared_ptr指针则不能实现对int的托管,造成了内存泄露
    func(shared_ptr(new int), g());    // 可能会出问题

weak_ptr特性

1. waek_ptr 设计的目的是为了协助shared_ptr工作

2. weak_ptr 可以从一个shared_ptr或weak_ptr对象构造

3. weak_ptr 构造和析构不会引起计数的增加或减少

 // use_count()函数引用计数问题
    shared_ptr sp(new int(10));
    weak_ptr wp(sp);        // 定义weak_ptr,并用sp进行初始化
    cout << wp.use_count() << endl;    // 输出结果为 1
    
    // expired()指针有效性问题
     shared_ptr sp(new int(10));
    weak_ptr wp(sp);
     if (wp.expired()) {
        cout << "weak_ptr无效,内存已经释放" << endl;
        }
     else {
        cout << "weak_ptr有效,内存未释放" << endl;
        }
     
     // lock()获取托管内存
    auto sp = make_shared(42);
    weak_ptr wp = sp;
     auto spt = wp.lock();    // 获取shared_ptr

     if (wp.expired()) {
        cout << "wp有效" << *spt << endl;    // 输出内容
     }

weak_ptr解决shared_ptr中的循环引用问题

shared_ptr在两个对象中的同一成员变量同时使用了一个shared_ptr,并将shared_ptr指向对方时,会造成循环引用,使引用计数失效,从而造成内存泄漏。

只需要将两个对象中的其中一个使用的shared_ptr换成weak_ptr就可解决问题

#include 
#include 
using namespace std;
class A;
class B;

class A {
public:
    std::weak_ptr bptr; // 修改为weak_ptr
    ~A() {
    cout << "A is deleted" << endl;
    }
};

class B {
public:
    std::shared_ptr aptr;
    ~B() {
    cout << "B is deleted" << endl;
    }
};
int main()
{
    {
    std::shared_ptr ap(new A);
    std::shared_ptr bp(new B);
    ap->bptr = bp;
    bp->aptr = ap;
    }
    cout<< "main leave" << endl;
    return 0;
}

你可能感兴趣的:(C++基础,c++,学习,开发语言)