shared_ptr總結(jié)

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

using namespace std;

/*
 1.shared_ptr允許多個(gè)指針指向同一個(gè)對(duì)象。
 2.shared_ptr定義在memory頭文件中。
 3.默認(rèn)初始化的智能指針中保存著一個(gè)空指針。
 4.智能指針的使用方式與普通指針類似,解引用一個(gè)智能指針返回它指向的對(duì)象咽扇,是對(duì)象,而不是一個(gè)指針。
 5.最安全的分配和使用動(dòng)態(tài)內(nèi)存的方法是調(diào)用一個(gè)名為make_shared的標(biāo)準(zhǔn)函數(shù)佳遣,
   此函數(shù)在動(dòng)態(tài)內(nèi)存中分配一個(gè)對(duì)象并初始化它识埋,返回指向此對(duì)象的shared_ptr。
 6.調(diào)用make_shared在定義在memory文件當(dāng)中零渐。
 7.調(diào)用make_shared<string>時(shí)窒舟,傳遞的參數(shù)必須與string的某個(gè)構(gòu)造函數(shù)相匹配,
   調(diào)用make_shared<int>時(shí)傳遞的參數(shù)必須能用來初始化一個(gè)int诵盼,以此類推惠豺。
   如果我們不傳遞任何參數(shù),對(duì)象就會(huì)進(jìn)行值初始化风宁。
 8.通常用auto定義一個(gè)對(duì)象來保存make_shared的結(jié)果
 9.若p.unique()為1洁墙,返回true,否則返回false戒财。
 10.當(dāng)進(jìn)行拷貝或賦值操作時(shí)热监,每隔shared_ptr都會(huì)記錄有多少個(gè)其他shared_ptr指向相同的對(duì)象,
    可以認(rèn)為每個(gè)shared_ptr都有一個(gè)關(guān)聯(lián)的計(jì)數(shù)器饮寞,通常稱其為引用計(jì)數(shù)孝扛,無論何時(shí)我們拷貝一個(gè)shared_ptr,
    計(jì)數(shù)器都會(huì)遞增幽崩。
 11.r = q苦始,q的引用計(jì)數(shù)增加,r的引用計(jì)數(shù)先遞減慌申,然后指向q指向的對(duì)象陌选,r的引用計(jì)數(shù)加1。
 12.shared_ptr析構(gòu)函數(shù)會(huì)遞減它所指向的引用計(jì)數(shù)蹄溉。如果引用計(jì)數(shù)變?yōu)?咨油,shared_ptr的析構(gòu)函數(shù)就會(huì)銷毀對(duì)象,
    并釋放它的內(nèi)存类缤。
 13.接受指針參數(shù)的智能指針構(gòu)造函數(shù)是explicit的臼勉,因此我們不能將一個(gè)內(nèi)置指針隱式轉(zhuǎn)換為一個(gè)智能指針,
    必須使用直接初始化形式來初始化一個(gè)智能指針餐弱。
 14.不能進(jìn)行內(nèi)置指針到智能指針的隱式轉(zhuǎn)換宴霸。
 15.默認(rèn)情況下,一個(gè)用來初始化智能指針的普通指針必須指向動(dòng)態(tài)內(nèi)存膏蚓,因?yàn)橹悄苤羔樐J(rèn)使用delete釋放它所關(guān)聯(lián)的對(duì)象瓢谢。
 16.不要使用get初始化另一個(gè)智能指針或?yàn)橹悄苤羔樫x值
 17.使用get返回的指針的代碼不能delete此指針
 18.shared_ptr沒有release函數(shù)
*/

class Student
{
public:
    Student() {
        cout << "調(diào)用Student的默認(rèn)構(gòu)造函數(shù) name:" << m_name << endl;
    }

    Student(string name) : m_name(name) {
        cout << "調(diào)用Student的自定義構(gòu)造函數(shù) name:" << m_name << endl;
    }

    Student(const Student &s) : m_name(s.m_name) {
        cout << "調(diào)用Student的拷貝構(gòu)造函數(shù) name:" << m_name << endl;
    }

    ~Student() {
        cout << "調(diào)用Student的析構(gòu)函數(shù) 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 = "許攸";
}

// 傳給函數(shù)一個(gè)臨時(shí)的shared_ptr,很可能導(dǎo)致錯(cuò)誤
void test_01()
{
    // test_local的實(shí)參是一個(gè)Student類的對(duì)象驮瞧,接收郭嘉的是test_local函數(shù)的形參
    // 當(dāng)執(zhí)行到test_local函數(shù)內(nèi)部時(shí)氓扛,對(duì)象郭嘉沒有被銷毀,直到test_local執(zhí)行完后,
    // Student對(duì)象才會(huì)被銷毀
    // 郭嘉的生命周期在test_local函數(shù)中
    test_local(Student("郭嘉"));

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

    /*
     * 合法采郎,但是s所指向的內(nèi)存會(huì)被釋放
     * 因?yàn)橛闷胀ㄖ羔榮初始化一個(gè)智能指針千所,智能指針?biāo)竷?nèi)存和普通指針s所指向內(nèi)存相同
     * 此智能指針創(chuàng)建后,test函數(shù)的形參接收Student的智能指針
     * 當(dāng)test函數(shù)調(diào)用過后蒜埋,智能指針將會(huì)引用計(jì)數(shù)減一淫痰,當(dāng)引用計(jì)數(shù)為0時(shí),釋放所指內(nèi)存
     * test執(zhí)行完成后整份,s指針指向的內(nèi)存釋放待错,但是s還是指向原來的內(nèi)存空間
    */
    // 形參接收實(shí)參創(chuàng)建的智能指針
    test(shared_ptr<Student> (s));
    if (s) {
        cout << "s is not nullptr 但s所指向的內(nèi)存已經(jīng)被釋放了" << endl;
    } else  {
        cout << "s is nullptr" << endl;
    }

    cout << __func__ << "函數(shù)結(jié)束" << endl;
}

// unique
void test_02()
{
    shared_ptr<Student> s1 = make_shared<Student>("衛(wèi)青");
    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__ << "函數(shù)結(jié)束" << 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__ << "函數(shù)結(jié)束" << endl;
}

// shared_ptr的use_count
void test_04()
{
    // Student("朱重八")當(dāng)做make_shared的參數(shù),是局部變量烈评,make_shared執(zhí)行完后火俄,Student("朱重八")要被釋放掉
    shared_ptr<Student> s1 = make_shared<Student>(Student("朱重八"));
    cout << "s1.name:" << s1->m_name << endl;

    shared_ptr<Student> s2 = make_shared<Student>(Student("朱標(biāo)"));
    cout << "s2.name:" << s2->m_name << endl;

    // use_count的效率很低,僅用于調(diào)試
    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__ << "函數(shù)結(jié)束" << endl;
}

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

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

    // 智能指針和智能指針內(nèi)保存的普通指針指向的地址不同
    cout << "s1.get:" << s1.get()
         << " s1:" << s1
         << " s:" << s
         << endl;

    // 智能指針和智能指針包含的普通指針讲冠,兩個(gè)指針的地址不同
    auto p = s1.get();
    cout << "&s1.get:" << &p
         << " &s1:" << &s1
         << endl;

    /*
     * 執(zhí)行完make_shared<Student>(*s);后瓜客,因?yàn)闆]有定義變量接受make_shared返回的臨時(shí)智能指針,
     * 所以智能指針銷毀
    */
    // 這里是深拷貝沟启,不是淺拷貝忆家,所有普通指針s所指向的內(nèi)存沒有被釋放
    make_shared<Student>(*s);
    std::cout << "func:" << __func__
              << " line:" << __LINE__
              << " s.name:" << s->m_name
              << endl;

    // 尚可喜return后不釋放犹菇,返回到調(diào)用函數(shù)當(dāng)中繼續(xù)使用
    return make_shared<Student>("尚可喜");
}

void test_05()
{
    auto s1 = new Student("吳應(yīng)熊");
    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__ << "函數(shù)結(jié)束" << endl;
}

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

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

    /*make_shared返回的結(jié)果沒有賦值給智能指針德迹,
     那么make_shared創(chuàng)建的智能指針就結(jié)束了生命周期,會(huì)調(diào)用析構(gòu)函數(shù)釋放內(nèi)存 */
    make_shared<Student>("蘇克薩哈");

    cout << __func__ << "函數(shù)結(jié)束" << endl;
}

// 判斷智能指針是否為空
void test_07()
{
    // 默認(rèn)初始化的智能指針中保存著一個(gè)空指針揭芍。
    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包含的指針為空胳搞,空指針調(diào)用empty函數(shù)崩潰
//    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等價(jià)于(*s1).m_name
    // s1.get()返回s1中保存的指針

    cout << __func__ << "函數(shù)結(jié)束" << endl;
}

void test_08()
{
    Student *s1 = new Student("多隆");
    cout << "s1->m_name:" << s1->m_name << " s1:" << s1 << endl;
    {
        // 這種方式創(chuàng)建的shared_ptr<Student>指針?biāo)竷?nèi)存地址和s1所指內(nèi)存地址是一樣的
        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所指的內(nèi)存已經(jīng)被釋放,所有不能訪問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__ << "函數(shù)結(jié)束" << 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__ << "函數(shù)結(jié)束" << endl;
}

void test_10()
{
    // 調(diào)用自定義構(gòu)造函數(shù)
    Student *s1 = new Student("岱宗");
    shared_ptr<Student> s2(s1);

    // 調(diào)用自定義構(gòu)造函數(shù)
    shared_ptr<Student> s3 = make_shared<Student>("宋江");
    shared_ptr<Student> s4(s3);

    cout << __func__ << "函數(shù)結(jié)束" << endl;
}

void test_11()
{
    unique_ptr<int> q(new int(10));
    // error:書上說這樣可以称杨,但是代碼里面不行
    // shared_ptr<int> p1(q);

    cout << __func__ << "函數(shù)結(jié)束" << endl;
}

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

    // 在test函數(shù)形參的引用計(jì)數(shù)為2肌毅,s1和形參指向同一塊內(nèi)存
    test(s1);

    cout << __func__ << "函數(shù)結(jié)束" << endl;
}

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

    // 錯(cuò)誤:使用get返回的指針不能使用delete釋放
    delete s2;
    s2 = nullptr;

    cout << __func__ << "函數(shù)結(jié)束" << endl;
}

void test_14()
{
    shared_ptr<Student> s1 = make_shared<Student>("甘興霸");
    // 先創(chuàng)建
    s1.reset(new Student("孫策"));

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

    cout << __func__ << "函數(shù)結(jié)束" << endl;
}

void test_15()
{
    // 默認(rèn)初始化的智能指針不調(diào)用構(gòu)造函數(shù),智能指針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>("關(guān)羽");

    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;
    }

    // 容器內(nèi)的shared_ptr只有調(diào)用erase悬而,才會(huì)引用計(jì)數(shù)減一
    for (auto it = vec.begin(); it != vec.end();) {
        it = vec.erase(it);
    }

    cout << "func:" << __func__ << " 結(jié)束" << endl;
}

void test_18()
{
    shared_ptr<Student> s1 = make_shared<Student>("孫悟空");
     // shared_ptr沒有release函數(shù)
     // 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;

    // 調(diào)用reset將sp1的引用計(jì)數(shù)減一
    sp1.reset();
    cout << "sp1.use_count:" << sp1.use_count()
         << " sp2.use_count:" << sp2.use_count()
         << endl;

    sp2.reset();

    cout << "func:" << __func__ << " 結(jié)束" << endl;
}

// 動(dòng)態(tài)分配的const對(duì)象
void test_20()
{
    const int *pi1 = new int();
    cout << "*pi1:" << *pi1 << endl;

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

    cout << "func:" << __func__ << " 結(jié)束" << 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;
}

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锭汛,隨后出現(xiàn)的幾起案子笨奠,更是在濱河造成了極大的恐慌,老刑警劉巖唤殴,帶你破解...
    沈念sama閱讀 211,743評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件般婆,死亡現(xiàn)場離奇詭異,居然都是意外死亡朵逝,警方通過查閱死者的電腦和手機(jī)蔚袍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,296評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來配名,“玉大人啤咽,你說我怎么就攤上這事晋辆。” “怎么了宇整?”我有些...
    開封第一講書人閱讀 157,285評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵栈拖,是天一觀的道長。 經(jīng)常有香客問我没陡,道長涩哟,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,485評(píng)論 1 283
  • 正文 為了忘掉前任盼玄,我火速辦了婚禮贴彼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘埃儿。我一直安慰自己器仗,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,581評(píng)論 6 386
  • 文/花漫 我一把揭開白布童番。 她就那樣靜靜地躺著精钮,像睡著了一般。 火紅的嫁衣襯著肌膚如雪剃斧。 梳的紋絲不亂的頭發(fā)上轨香,一...
    開封第一講書人閱讀 49,821評(píng)論 1 290
  • 那天,我揣著相機(jī)與錄音幼东,去河邊找鬼臂容。 笑死,一個(gè)胖子當(dāng)著我的面吹牛根蟹,可吹牛的內(nèi)容都是我干的脓杉。 我是一名探鬼主播,決...
    沈念sama閱讀 38,960評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼简逮,長吁一口氣:“原來是場噩夢啊……” “哼球散!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起散庶,我...
    開封第一講書人閱讀 37,719評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤蕉堰,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后督赤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體嘁灯,經(jīng)...
    沈念sama閱讀 44,186評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,516評(píng)論 2 327
  • 正文 我和宋清朗相戀三年躲舌,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了丑婿。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,650評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖羹奉,靈堂內(nèi)的尸體忽然破棺而出秒旋,到底是詐尸還是另有隱情,我是刑警寧澤诀拭,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布迁筛,位于F島的核電站,受9級(jí)特大地震影響耕挨,放射性物質(zhì)發(fā)生泄漏细卧。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,936評(píng)論 3 313
  • 文/蒙蒙 一筒占、第九天 我趴在偏房一處隱蔽的房頂上張望贪庙。 院中可真熱鬧,春花似錦翰苫、人聲如沸止邮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,757評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽导披。三九已至,卻和暖如春埃唯,著一層夾襖步出監(jiān)牢的瞬間撩匕,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,991評(píng)論 1 266
  • 我被黑心中介騙來泰國打工筑凫, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留滑沧,地道東北人并村。 一個(gè)月前我還...
    沈念sama閱讀 46,370評(píng)論 2 360
  • 正文 我出身青樓巍实,卻偏偏與公主長得像,于是被迫代替她去往敵國和親哩牍。 傳聞我的和親對(duì)象是個(gè)殘疾皇子棚潦,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,527評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容