六一的部落格


关关难过关关过,前路漫漫亦灿灿。



引用计数 reference count


shared_ptr的计数器

管理同一个动态对象的shared_ptr拥有相同的计数器, 该计数器指示了管理该动态对象的shared_ptr个数


计数器递增的情景

  • 使用一个shared_ptr初始化另一个shared_ptr时

    sp1的计数器递增, sp1和sp2共用计数器
    1shared_ptr<T> sp2(sp1);
  • 使用一个shared_ptr为另一个shared_ptr赋值时

    sp2的计数器递增, sp1和sp2拥有相同的计数器, sp1和sp2指向相同对象
    1sp1 = sp2;

认为管理该动态对象的shared_ptr增加


计数器递减的情景

  • 为shared_ptr赋值

    sp1的原计数器递减
    1sp1 = sp2;
  • 销毁shared_ptr时
    1{
    2    sp;
    3}
    认为管理该动态对象的shared_ptr减少

如果计数器递减为0, 销毁shared_ptr管理的动态对象

多个shared_ptr联合管理一个动态对象; 最后一个shared_ptr被销毁时,销毁动态对象


shared_ptr作为函数的参数和返回值


作为函数的参数

需注意shared_ptr的生存期

1void process(shared_ptr<int> ptr) {}
2
3int *x(new int(1024));
4process(shared_ptr<int>(x));    // 动态对象已被销毁
5int j = *x;                     // 错误: 访问非法内存

作为函数的返回类型

对于shared_ptr管理的动态对象,shared_ptr类保证只要有任何shared_ptr对象引用还在引用它,它就不会被销毁

 1shared_ptr<Foo> factory(T arg)
 2{
 3    return make_shared<Foo>(arg);        // 使用arg构建动态对象,由shared_ptr管理动态对象:在适当的时候释放
 4}
 5
 6void use_factory(T arg)
 7{
 8    shared_ptr<Foo> p = factory(arg);   // 由局部变量p管理内存
 9}
10// 函数结束,将shared_ptr对象p销毁; 销毁p时,递减引用计数并检查其是否为0; 为0则对p指向的动态对象调用析构函数
11// 此例中, 销毁p管理的动态对象
12
13shared_ptr<Foo> use_factory(T arg)
14{
15    shared_ptr<Foo> p = factory(arg);
16    return p;                           // 将p的拷贝作为返回值时, 会递增引用计数
17}
18// 函数结束, 销毁p, 而引用计数不为0; 此时, 动态对象还未被销毁

make_shared操作: 为shared_ptr申请动态内存

模板函数

返回一个shared_ptr对象

使用make_shared的参数匹配对象的构造函数; 参数列表为空时值初始化动态对象

1auto sp = make_shared<T>();
2auto sp = make_shared<T>(args);

示例

1shared_ptr<int> p1 = make_shared<int>();
2shared_ptr<int> p2 = make_shared<int>(42);
3auto p3 = make_shared<vector<string>>();
4shared_ptr<string> p4 = make_shared<string>(10, '9');
5
6cout << *p1 << endl;
7cout << *p2 << endl;
8cout << *p4 << endl;

use_count操作: 获取引用计数

返回联合管理该动态对象的shared_ptr个数

1sp.use_count();

unique操作: 判断是否有其他shared_ptr联合管理该动态对象

返回类型为bool

shared_ptr唯一返回true; 否则返回false

1p.unique();

多个shared_ptr联合管理动态对象

对shared_ptr对象执行拷贝和赋值操作时, 会更新动态对象的引用计数


使用一个shared_ptr初始化另一个shared_ptr

使用sp1初始化sp2

1shared_ptr<T> sp1 = make_shared<T>(args);       // sp1指向动态对象A, 引用计数为X
2shared_ptr<T> sp2(sp1);                         // 递增动态对象A的引用计数, 为X+1; sp1和sp2共用引用计数

使用一个shared_ptr为另一个shared_ptr赋值

使用sp2为sp1赋值

1sp1 = sp2;

第一种说明方法, 分情况讨论:

  1. sp1和sp2均为空
  2. sp1为空; sp2指向动态对象B, 引用计数为Y

    递增Y, sp1和sp2共用引用计数
  3. sp1指向动态对象A, 引用计数为X; sp2为空

    递减X: 如果X变作0, 销毁A
  4. sp1指向动态对象A, 引用计数为X; sp2指向动态对象B, 引用计数为Y

    递减X: 如果X变作0, 销毁A

    递增Y, sp1和sp2共用引用计数

第二种说明方法:

  • sp2指向动态对象B: 如果B存在,递增引用计数Y
  • sp1指向动态对象A: 如果A存在, 递减引用计数X; 如果X变作0, 对A调用析构函数

shared_ptr作为函数的参数和返回值


创建shared_ptr: 使用移后源初始化

1shared_ptr<T> sp2(std::move(sp1));

sp1被置空


示例

仅供参考

 1#include <iostream>
 2#include <ostream>
 3#include <string>
 4#include <vector>
 5#include <memory>
 6
 7using namespace std;
 8
 9class Foo
10{
11    friend ostream &operator<<(ostream &os, const Foo &f);
12
13public:
14    Foo(string _name) : name(_name) {}
15    ~Foo() { cout << "Call ~Foo for " << *this << endl << endl; }
16
17private:
18    string name;
19};
20
21ostream &operator<<(ostream &os, const Foo &f)
22{
23    os << f.name;
24    return os;
25}
26
27void DeleteFoo(Foo *f)
28{
29    cout << "call " << __FUNCTION__ << " for " << *f << endl;
30    delete f; // 调用~Foo()
31}
32
33int main()
34{
35    auto p = new Foo("Peter");
36
37    shared_ptr<Foo> sp1(p), sp2(sp1);
38
39    cout << "*sp2 equals " << *sp2 << endl;
40
41    shared_ptr<Foo> sp3(std::move(sp1));
42
43    if (sp1 == nullptr) cout << "sp1 is null.\n";
44    if (sp2 == sp3) cout << "equal.\n";
45
46    cout << sp2.use_count() << "\t" << sp3.use_count() << endl;
47
48    cout << "main finished.\n";
49    return 0;
50}

输出

*sp2 equals Peter
sp1 is null.
equal.
2	2
main finished.
Call ~Foo for Peter

智能指针: shared_ptr


引用计数 reference count


shared_ptr的计数器

管理同一个动态对象的shared_ptr拥有相同的计数器, 该计数器指示了管理该动态对象的shared_ptr个数


计数器递增的情景

  • 使用一个shared_ptr初始化另一个shared_ptr时

    sp1的计数器递增, sp1和sp2共用计数器
    1shared_ptr<T> sp2(sp1);
  • 使用一个shared_ptr为另一个shared_ptr赋值时

    sp2的计数器递增, sp1和sp2拥有相同的计数器, sp1和sp2指向相同对象
    1sp1 = sp2;

认为管理该动态对象的shared_ptr增加


计数器递减的情景

  • 为shared_ptr赋值

    sp1的原计数器递减
    1sp1 = sp2;
  • 销毁shared_ptr时
    1{
    2    sp;
    3}
    认为管理该动态对象的shared_ptr减少

如果计数器递减为0, 销毁shared_ptr管理的动态对象

多个shared_ptr联合管理一个动态对象; 最后一个shared_ptr被销毁时,销毁动态对象


shared_ptr作为函数的参数和返回值


作为函数的参数

需注意shared_ptr的生存期

1void process(shared_ptr<int> ptr) {}
2
3int *x(new int(1024));
4process(shared_ptr<int>(x));    // 动态对象已被销毁
5int j = *x;                     // 错误: 访问非法内存

作为函数的返回类型

对于shared_ptr管理的动态对象,shared_ptr类保证只要有任何shared_ptr对象引用还在引用它,它就不会被销毁

 1shared_ptr<Foo> factory(T arg)
 2{
 3    return make_shared<Foo>(arg);        // 使用arg构建动态对象,由shared_ptr管理动态对象:在适当的时候释放
 4}
 5
 6void use_factory(T arg)
 7{
 8    shared_ptr<Foo> p = factory(arg);   // 由局部变量p管理内存
 9}
10// 函数结束,将shared_ptr对象p销毁; 销毁p时,递减引用计数并检查其是否为0; 为0则对p指向的动态对象调用析构函数
11// 此例中, 销毁p管理的动态对象
12
13shared_ptr<Foo> use_factory(T arg)
14{
15    shared_ptr<Foo> p = factory(arg);
16    return p;                           // 将p的拷贝作为返回值时, 会递增引用计数
17}
18// 函数结束, 销毁p, 而引用计数不为0; 此时, 动态对象还未被销毁

make_shared操作: 为shared_ptr申请动态内存

模板函数

返回一个shared_ptr对象

使用make_shared的参数匹配对象的构造函数; 参数列表为空时值初始化动态对象

1auto sp = make_shared<T>();
2auto sp = make_shared<T>(args);

示例

1shared_ptr<int> p1 = make_shared<int>();
2shared_ptr<int> p2 = make_shared<int>(42);
3auto p3 = make_shared<vector<string>>();
4shared_ptr<string> p4 = make_shared<string>(10, '9');
5
6cout << *p1 << endl;
7cout << *p2 << endl;
8cout << *p4 << endl;

use_count操作: 获取引用计数

返回联合管理该动态对象的shared_ptr个数

1sp.use_count();

unique操作: 判断是否有其他shared_ptr联合管理该动态对象

返回类型为bool

shared_ptr唯一返回true; 否则返回false

1p.unique();

多个shared_ptr联合管理动态对象

对shared_ptr对象执行拷贝和赋值操作时, 会更新动态对象的引用计数


使用一个shared_ptr初始化另一个shared_ptr

使用sp1初始化sp2

1shared_ptr<T> sp1 = make_shared<T>(args);       // sp1指向动态对象A, 引用计数为X
2shared_ptr<T> sp2(sp1);                         // 递增动态对象A的引用计数, 为X+1; sp1和sp2共用引用计数

使用一个shared_ptr为另一个shared_ptr赋值

使用sp2为sp1赋值

1sp1 = sp2;

第一种说明方法, 分情况讨论:

  1. sp1和sp2均为空
  2. sp1为空; sp2指向动态对象B, 引用计数为Y

    递增Y, sp1和sp2共用引用计数
  3. sp1指向动态对象A, 引用计数为X; sp2为空

    递减X: 如果X变作0, 销毁A
  4. sp1指向动态对象A, 引用计数为X; sp2指向动态对象B, 引用计数为Y

    递减X: 如果X变作0, 销毁A

    递增Y, sp1和sp2共用引用计数

第二种说明方法:

  • sp2指向动态对象B: 如果B存在,递增引用计数Y
  • sp1指向动态对象A: 如果A存在, 递减引用计数X; 如果X变作0, 对A调用析构函数

shared_ptr作为函数的参数和返回值


创建shared_ptr: 使用移后源初始化

1shared_ptr<T> sp2(std::move(sp1));

sp1被置空


示例

仅供参考

 1#include <iostream>
 2#include <ostream>
 3#include <string>
 4#include <vector>
 5#include <memory>
 6
 7using namespace std;
 8
 9class Foo
10{
11    friend ostream &operator<<(ostream &os, const Foo &f);
12
13public:
14    Foo(string _name) : name(_name) {}
15    ~Foo() { cout << "Call ~Foo for " << *this << endl << endl; }
16
17private:
18    string name;
19};
20
21ostream &operator<<(ostream &os, const Foo &f)
22{
23    os << f.name;
24    return os;
25}
26
27void DeleteFoo(Foo *f)
28{
29    cout << "call " << __FUNCTION__ << " for " << *f << endl;
30    delete f; // 调用~Foo()
31}
32
33int main()
34{
35    auto p = new Foo("Peter");
36
37    shared_ptr<Foo> sp1(p), sp2(sp1);
38
39    cout << "*sp2 equals " << *sp2 << endl;
40
41    shared_ptr<Foo> sp3(std::move(sp1));
42
43    if (sp1 == nullptr) cout << "sp1 is null.\n";
44    if (sp2 == sp3) cout << "equal.\n";
45
46    cout << sp2.use_count() << "\t" << sp3.use_count() << endl;
47
48    cout << "main finished.\n";
49    return 0;
50}

输出

*sp2 equals Peter
sp1 is null.
equal.
2	2
main finished.
Call ~Foo for Peter