shared_ptr总结

#include <iostream>
#include <memory>
#include <vector>

using namespace std;

/*
 1.shared_ptr允许多个指针指向同一个对象。
 2.shared_ptr定义在memory头文件中。
 3.默认初始化的智能指针中保存着一个空指针。
 4.智能指针的使用方式与普通指针类似,解引用一个智能指针返回它指向的对象,是对象,而不是一个指针。
 5.最安全的分配和使用动态内存的方法是调用一个名为make_shared的标准函数,
   此函数在动态内存中分配一个对象并初始化它,返回指向此对象的shared_ptr。
 6.调用make_shared在定义在memory文件当中。
 7.调用make_shared<string>时,传递的参数必须与string的某个构造函数相匹配,
   调用make_shared<int>时传递的参数必须能用来初始化一个int,以此类推。
   如果我们不传递任何参数,对象就会进行值初始化。
 8.通常用auto定义一个对象来保存make_shared的结果
 9.若p.unique()为1,返回true,否则返回false。
 10.当进行拷贝或赋值操作时,每隔shared_ptr都会记录有多少个其他shared_ptr指向相同的对象,
    可以认为每个shared_ptr都有一个关联的计数器,通常称其为引用计数,无论何时我们拷贝一个shared_ptr,
    计数器都会递增。
 11.r = q,q的引用计数增加,r的引用计数先递减,然后指向q指向的对象,r的引用计数加1。
 12.shared_ptr析构函数会递减它所指向的引用计数。如果引用计数变为0,shared_ptr的析构函数就会销毁对象,
    并释放它的内存。
 13.接受指针参数的智能指针构造函数是explicit的,因此我们不能将一个内置指针隐式转换为一个智能指针,
    必须使用直接初始化形式来初始化一个智能指针。
 14.不能进行内置指针到智能指针的隐式转换。
 15.默认情况下,一个用来初始化智能指针的普通指针必须指向动态内存,因为智能指针默认使用delete释放它所关联的对象。
 16.不要使用get初始化另一个智能指针或为智能指针赋值
 17.使用get返回的指针的代码不能delete此指针
 18.shared_ptr没有release函数
*/

class Student
{
public:
    Student() {
        cout << "调用Student的默认构造函数 name:" << m_name << endl;
    }

    Student(string name) : m_name(name) {
        cout << "调用Student的自定义构造函数 name:" << m_name << endl;
    }

    Student(const Student &s) : m_name(s.m_name) {
        cout << "调用Student的拷贝构造函数 name:" << m_name << endl;
    }

    ~Student() {
        cout << "调用Student的析构函数 name:" << m_name << endl;
    }
    string m_name;
    int a;
};

auto deleter = [](Student *s) {
    std::cout << "deleter name:" << s->m_name << endl;
};

void test(shared_ptr<Student> s)
{
    cout << "func:" << __func__
        << " line:" << __LINE__
        << " s:" << s
        << " s.use_count:"
        << s.use_count()
        << endl;

    if (s.unique()) {
        std::cout << "s is unique" << endl;
    } else {
        std::cout << "s is not unique" << endl;
    }
}

void test_local(Student s) {
    cout << "func:" << __func__ << " line:" << __LINE__ << endl;
    s.m_name = "许攸";
}

// 传给函数一个临时的shared_ptr,很可能导致错误
void test_01()
{
    // test_local的实参是一个Student类的对象,接收郭嘉的是test_local函数的形参
    // 当执行到test_local函数内部时,对象郭嘉没有被销毁,直到test_local执行完后,
    // Student对象才会被销毁
    // 郭嘉的生命周期在test_local函数中
    test_local(Student("郭嘉"));

    Student *s = new Student("燕青");

    /*
     * 合法,但是s所指向的内存会被释放
     * 因为用普通指针s初始化一个智能指针,智能指针所指内存和普通指针s所指向内存相同
     * 此智能指针创建后,test函数的形参接收Student的智能指针
     * 当test函数调用过后,智能指针将会引用计数减一,当引用计数为0时,释放所指内存
     * test执行完成后,s指针指向的内存释放,但是s还是指向原来的内存空间
    */
    // 形参接收实参创建的智能指针
    test(shared_ptr<Student> (s));
    if (s) {
        cout << "s is not nullptr 但s所指向的内存已经被释放了" << endl;
    } else  {
        cout << "s is nullptr" << endl;
    }

    cout << __func__ << "函数结束" << endl;
}

// unique
void test_02()
{
    shared_ptr<Student> s1 = make_shared<Student>("卫青");
    if (s1.unique()) {
        std::cout << "a1 is unique" << endl;
    } else {
        std::cout << "a1 is not unique" << endl;
    }

    std::cout << endl;

    shared_ptr<Student> s2 = s1;
    if (s2.unique()) {
        std::cout << "s2 is unique" << endl;
    } else {
        std::cout << "s2 is not unique use_count:" << s2.use_count() << endl;
    }

    cout << "s1.name:" << s1->m_name << endl;
    cout << "s2.name:" << s2->m_name << endl;
    cout << "s1:" << s2 << " s2:" << s2 << endl;

    cout << __func__ << "函数结束" << endl;
}

// 添加删除器
void test_03()
{
    shared_ptr<Student> s1(new Student("步惊云"), deleter);

    cout << "s1:" << s1 << endl;

    /*
     * error:
     * no matching function for call to
     * 'std::__cxx11::basic_string<char>::basic_string(std::__cxx11::basic_string<char>*, main()::<lambda(std::__cxx11::string*)>&)'
     * { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
    */
    // make_shared不允许自定义删除器
    // shared_ptr<Student> s2 = make_shared<Student>(new Student("步惊云"), deleter);

    // 添加删除器
    s1.reset(new Student("步天"), deleter);
    cout << "s1.name:" << s1->m_name << " s1:" << s1 << endl;

    cout << __func__ << "函数结束" << endl;
}

// shared_ptr的use_count
void test_04()
{
    // Student("朱重八")当做make_shared的参数,是局部变量,make_shared执行完后,Student("朱重八")要被释放掉
    shared_ptr<Student> s1 = make_shared<Student>(Student("朱重八"));
    cout << "s1.name:" << s1->m_name << endl;

    shared_ptr<Student> s2 = make_shared<Student>(Student("朱标"));
    cout << "s2.name:" << s2->m_name << endl;

    // use_count的效率很低,仅用于调试
    cout << "s1.use_count:" <<  s1.use_count() << endl;
    cout << "s2.use_count:" <<  s2.use_count() << endl;

    s1 = s2;
    cout << "s1.use_count:" <<  s1.use_count() << endl;
    cout << "s2.use_count:" <<  s2.use_count() << endl;

    cout << __func__ << "函数结束" << endl;
}

shared_ptr<Student> FuncCreateStudent(Student *s)
{
    cout << "func:" << __func__
         << " line:" << __LINE__ << endl;

    auto s1 = make_shared<Student>(*s);

    // 智能指针和智能指针内保存的普通指针指向的地址不同
    cout << "s1.get:" << s1.get()
         << " s1:" << s1
         << " s:" << s
         << endl;

    // 智能指针和智能指针包含的普通指针,两个指针的地址不同
    auto p = s1.get();
    cout << "&s1.get:" << &p
         << " &s1:" << &s1
         << endl;

    /*
     * 执行完make_shared<Student>(*s);后,因为没有定义变量接受make_shared返回的临时智能指针,
     * 所以智能指针销毁
    */
    // 这里是深拷贝,不是浅拷贝,所有普通指针s所指向的内存没有被释放
    make_shared<Student>(*s);
    std::cout << "func:" << __func__
              << " line:" << __LINE__
              << " s.name:" << s->m_name
              << endl;

    // 尚可喜return后不释放,返回到调用函数当中继续使用
    return make_shared<Student>("尚可喜");
}

void test_05()
{
    auto s1 = new Student("吴应熊");
    auto s2 = FuncCreateStudent(s1);
    std::cout << "s1->m_name:" << s1->m_name
              << " s2->m_name:" << s2->m_name
              << endl;
    std::cout << "s2.use_count:" << s2.use_count() << endl;

    cout << __func__ << "函数结束" << endl;
}

void test_06()
{
    Student *s1 = new Student("鳌拜");
    auto s2 = make_shared<Student>(*s1);

    auto s3 = new Student("索尼");
    make_shared<Student>(*(s3));

    /*make_shared返回的结果没有赋值给智能指针,
     那么make_shared创建的智能指针就结束了生命周期,会调用析构函数释放内存 */
    make_shared<Student>("苏克萨哈");

    cout << __func__ << "函数结束" << endl;
}

// 判断智能指针是否为空
void test_07()
{
    // 默认初始化的智能指针中保存着一个空指针。
    shared_ptr<Student> s1;
    if (s1) {
        cout << "s1 is not nullptr" << endl;
    } else {
        cout << "s1 is nullptr" << endl;
    }

    shared_ptr<string> str;

    cout << "func:" << __func__ << " line:" << __LINE__ << endl;

    // str包含的指针为空,空指针调用empty函数崩溃
//    if (str->empty()) {
//        cout << "str->empty is empty " << endl;
//    }

    cout << "func:" << __func__ << " line:" << __LINE__ << endl;

    shared_ptr<Student> s2 = make_shared<Student>("遏必隆");
    // s1->m_name等价于(*s1).m_name
    // s1.get()返回s1中保存的指针

    cout << __func__ << "函数结束" << endl;
}

void test_08()
{
    Student *s1 = new Student("多隆");
    cout << "s1->m_name:" << s1->m_name << " s1:" << s1 << endl;
    {
        // 这种方式创建的shared_ptr<Student>指针所指内存地址和s1所指内存地址是一样的
        shared_ptr<Student> s2(s1);
        Student *s3 = s2.get();
        cout << "s2->m_name:" << s2->m_name << " s2->use_count:" << s2.use_count() << endl;
        cout << "s1:" << s1 << " s2:" << s2 << " s3:" << s3 << endl;
        cout << endl;
    }

    // a1所指的内存已经被释放,所有不能访问a1的成员变量
    // cout << "s1->m_name:" << s1->m_name << endl;

    Student *s4 = new Student("豪格");
    cout << "s4->m_name:" << s4->m_name << " s4:" << s4 << endl;
    {
        auto s5 = make_shared<Student>(*s4);
        cout << "s5->m_name:" << s5->m_name
             << " s5->use_count:" << s5.use_count()
             << endl;
        cout << endl;
    }

    cout << "s1->m_name:" << s1->m_name << " s1:" << s1 << endl;

    cout << __func__ << "函数结束" << endl;
}

// 智能指针解引用
void test_09()
{
    shared_ptr<int> p1(new int(10));
    shared_ptr<int> p2 = make_shared<int>(10);

    cout << "*p1:" << *p1 << endl;
    cout << "*p2:" << *p2 << endl;

    cout << __func__ << "函数结束" << endl;
}

void test_10()
{
    // 调用自定义构造函数
    Student *s1 = new Student("岱宗");
    shared_ptr<Student> s2(s1);

    // 调用自定义构造函数
    shared_ptr<Student> s3 = make_shared<Student>("宋江");
    shared_ptr<Student> s4(s3);

    cout << __func__ << "函数结束" << endl;
}

void test_11()
{
    unique_ptr<int> q(new int(10));
    // error:书上说这样可以,但是代码里面不行
    // shared_ptr<int> p1(q);

    cout << __func__ << "函数结束" << endl;
}

void test_12()
{
    shared_ptr<Student> s1 = make_shared<Student>("甘宁");
    cout << "s1:" << s1 << endl;

    // 在test函数形参的引用计数为2,s1和形参指向同一块内存
    test(s1);

    cout << __func__ << "函数结束" << endl;
}

void test_13()
{
    shared_ptr<Student> s1 = make_shared<Student>("s1");
    Student *s2 = s1.get();

    // 错误:使用get返回的指针不能使用delete释放
    delete s2;
    s2 = nullptr;

    cout << __func__ << "函数结束" << endl;
}

void test_14()
{
    shared_ptr<Student> s1 = make_shared<Student>("甘兴霸");
    // 先创建
    s1.reset(new Student("孙策"));

    cout << "s1.name:" << s1->m_name << endl;

    cout << __func__ << "函数结束" << endl;
}

void test_15()
{
    // 默认初始化的智能指针不调用构造函数,智能指针s1为空,智能指针中保存空指针
    shared_ptr<Student> s1;
    if (s1) {
        cout << "s1不为空" << endl;
    } else {
        cout << "s1为空" << endl;
    }

    shared_ptr<Student> s2 = make_shared<Student>("张飞");
    if (s2) {
        cout << "s2不为空 name:" << s2->m_name << endl;
    } else {
        cout << "s2为空" << endl;
    }

    // 智能指针s3不为空
    shared_ptr<Student> s3 = make_shared<Student>();
    if (s3) {
        cout << "s3不为空 name:" << s3->m_name << endl;
    } else {
        cout << "s3为空" << endl;
    }
}

void test_16(vector<shared_ptr<Student>> &vec)
{
    auto s1 = make_shared<Student>("张飞");
    auto s2 = make_shared<Student>("刘备");
    auto s3 = make_shared<Student>("关羽");

    cout << "s1.a:" << s1->a << endl;

    vec.push_back(s1);
    vec.push_back(s2);
    vec.push_back(s3);

    cout << "s1.use_count:" << s1.use_count() << endl;
    cout << "s2.use_count:" << s2.use_count() << endl;
    cout << "s3.use_count:" << s3.use_count() << endl;
}

void test_17(vector<shared_ptr<Student>> &vec)
{
    for (size_t i = 0; i < vec.size(); i++) {
        cout << "func:" << __func__
             << " line:" << __LINE__
             << "name:" << vec[i]->m_name
             << " use_count:" << vec[i].use_count()
             << endl;
    }

    for (auto v : vec) {
        cout << "v.name:" << v->m_name
             << " use_count:" << v.use_count()
             << endl;
    }

    for (size_t i = 0; i < vec.size(); i++) {
        cout << "func:" << __func__
             << " line:" << __LINE__
             << "name:" << vec[i]->m_name
             << " use_count:" << vec[i].use_count()
             << endl;
    }

    // 容器内的shared_ptr只有调用erase,才会引用计数减一
    for (auto it = vec.begin(); it != vec.end();) {
        it = vec.erase(it);
    }

    cout << "func:" << __func__ << " 结束" << endl;
}

void test_18()
{
    shared_ptr<Student> s1 = make_shared<Student>("孙悟空");
     // shared_ptr没有release函数
     // s1.release();
}

void test_19()
{
    shared_ptr<Student> sp1 = make_shared<Student>("孙悟空");
    shared_ptr<Student> sp2 = sp1;
    cout << "sp1.use_count:" << sp1.use_count()
         << " sp2.use_count:" << sp2.use_count()
         << endl;

    // 调用reset将sp1的引用计数减一
    sp1.reset();
    cout << "sp1.use_count:" << sp1.use_count()
         << " sp2.use_count:" << sp2.use_count()
         << endl;

    sp2.reset();

    cout << "func:" << __func__ << " 结束" << endl;
}

// 动态分配的const对象
void test_20()
{
    const int *pi1 = new int();
    cout << "*pi1:" << *pi1 << endl;

    pi1 = new int(11);
    cout << "*pi1:" << *pi1 << endl;

    cout << "func:" << __func__ << " 结束" << endl;
}

int main()
{
    system("chcp 65001");

    // test_00();
    // test_01();
    // test_02();
    // test_03();
    // test_04();
    // test_05();
    // test_06();
    // test_07();
    // test_08();
    // test_09();
    // test_10();
    // test_11();
    // test_12();
    // test_13();
    // test_14();

    vector<shared_ptr<Student>> vec;
    // test_16(vec);
    // test_17(vec);
    // test_18();
    // test_19();
    test_20();
    return 0;
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,809评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,189评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,290评论 0 359
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,399评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,425评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,116评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,710评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,629评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,155评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,261评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,399评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,068评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,758评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,252评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,381评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,747评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,402评论 2 358

推荐阅读更多精彩内容