六一的部落格


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



删除器是一个可调用对象 deleter


使用内置指针初始化shared_ptr时, 为动态对象绑定删除器


删除器为可调用对象

1shared_ptr<T> sp(p, d);

示例

销毁动态对象时, 将内置指针传入删除器, 由删除器负责销毁动态对象

  1. 删除器的参数为内置指针类型
  2. 删除器负责销毁动态对象: 对指针指向delete运算

    实际还是使用对象的析构函数销毁对象
  3. 删除器可以完成其他所需操作

删除器只对绑定的动态对象有效

 1#include <iostream>
 2#include <ostream>
 3#include <string>
 4#include <vector>
 5#include <memory>
 6
 7using std::cout;
 8using std::endl;
 9using std::string;
10using std::ostream;
11
12class Foo
13{
14  friend ostream &operator<<(ostream &os, const Foo &f);  
15public:
16  Foo(string _name): name(_name) {}
17  ~Foo() { cout << "Call ~Foo for " << *this << endl << endl; }
18private:
19  string name;
20};
21
22ostream &operator<<(ostream &os, const Foo &f)
23{
24  os << f.name;
25  return os;
26}
27
28void DeleteFoo(Foo *f)
29{
30  cout << "call " << __FUNCTION__ << " for " << *f << endl;
31  delete f; // 调用~Foo()
32}
33
34int main(int argc, const char * argv[]) {
35  Foo f("Kate");
36  auto p = new Foo("Peter");
37  std::shared_ptr<Foo> f2(p, DeleteFoo); // 为Peter绑定删除器
38
39  f2 = make_shared<Foo>("Mary");         // 为Peter调用删除器, 删除器调用析构函数
40
41  f2 = nullptr;                          // 为Mary调用析构函数
42
43  cout << "main finished.\n";
44  return 0;
45}                                        // main函数结束才为Kate调用析构函数

输出

call DeleteFoo for Peter
Call ~Foo for Peter

Call ~Foo for Mary

main finished.
Call ~Foo for Kate

善用shared_ptr机制: 使用删除器管理非动态对象

  1. shared_ptr指向非动态对象
  2. 销毁shared_ptr时,对管理对象调用删除器

示例

使用shared_ptr管理connection

销毁shared_ptr时,对connection调用end_connection: connection仍存在,可再次使用

1void end_connection(connection *p) { disconnect(*p); }
2
3void f(destination &d)
4{
5    connection c = connect(&d);
6    shared_ptr<connection> p(&c, end_connection); // 销毁p时会对c调用end_connection
7}

shared_ptr接管动态对象时, 为动态对象绑定删除器

reset

提供重载版本: 第一个参数的缺省值为nullptr,第二个参数的缺省值为delete

  1. 形参列表为空: 将shared_ptr置空

    如果需要销毁动态对象, 使用delete运算符

  2. 传入内置指针: 从内置指针接管动态对象

    免去显式转换

    如果需要销毁动态对象, 使用delete运算符

  3. 传入内置指针和删除器: 从内置指针接管动态对象, 并为该动态对象绑定删除器

    之后删除该动态对象时, 使用删除器

    联合管理同一动态对象的计数器和删除器(如有绑定)是共用的

1sp.reset();
2// =>
3// sp = nullptr;
4
5sp.reset(p);
6// =>
7// sp = shared_ptr<T>(p);
8
9sp.reset(p, d);

示例

 1#include <iostream>
 2#include <string>
 3#include <vector>
 4#include <memory>
 5
 6using std::cout;
 7using std::endl;
 8using std::string;
 9
10void DeleteString(string *ps)
11{
12    if (ps) {
13        cout << "Delete " << *ps << endl << endl;
14        delete ps;
15    }
16}
17
18void DeleteString1(string *ps)
19{
20    cout << "This is " << __FUNCTION__ << ": ";
21    DeleteString(ps);
22}
23
24void DeleteString2(string *ps)
25{
26    cout << "This is " << __FUNCTION__ << ": ";
27    DeleteString(ps);
28}
29
30int main(int argc, const char * argv[])
31{
32    auto p = new string("Hat");
33    auto p2 = new string("Shoe");
34    std::shared_ptr<string> sp(p, DeleteString1); // 为Hat绑定删除器DeleteString1
35    sp.reset(p2, DeleteString2);                  // 为Hat调用删除器DeleteString1; 为Shoe绑定删除器DeleteString2
36
37    auto sp2 = sp;
38    sp = nullptr;
39    cout << "main finished.\n\n";
40    return 0;
41}                                                 // 为Shoe调用删除器DeleteString2

输出

This is DeleteString1: Delete Hat

main finished.

This is DeleteString2: Delete Shoe

注意: 使用一个shared_ptr初始化另一个shared_ptr时, 传入删除器

P413提到了该操作

1shared_ptr<T> sp1(sp2, d);

想要探究sp2所指动态对象的销毁途径, 但无法正确执行该操作. 做了以下尝试, 皆不成:

  1. 只sp2拥有删除器

    1auto p = new Foo("Peter");
    2shared_ptr<Foo> sp1(p);
    3
    4shared_ptr<Foo> sp2(sp1, DeleteFoo);   // 报错: no known conversion from 'shared_ptr<Foo>' to 'std::nullptr_t'
    5
    6// 仅说明意图
    7sp2 = nullptr;
  2. sp1和sp2拥有相同的删除器

    1auto p = new Foo("Peter");
    2shared_ptr<Foo> sp1(p, DeleteFoo);     // 为Peter绑定删除器
    3
    4shared_ptr<Foo> sp2(sp1, DeleteFoo);   // 报错: no known conversion from 'shared_ptr<Foo>' to 'std::nullptr_t'
    
  3. sp2为移后源

    1auto p = new Foo("Peter");
    2shared_ptr<Foo> sp1(p);
    3
    4shared_ptr<Foo> sp2(std::move(sp1), DeleteFoo); // 报错: no known conversion from 'typename remove_reference<shared_ptr<Foo> &>::type' (aka 'std::shared_ptr<Foo>') to 'std::nullptr_t'
    

shared_ptr与删除器


删除器是一个可调用对象 deleter


使用内置指针初始化shared_ptr时, 为动态对象绑定删除器


删除器为可调用对象

1shared_ptr<T> sp(p, d);

示例

销毁动态对象时, 将内置指针传入删除器, 由删除器负责销毁动态对象

  1. 删除器的参数为内置指针类型
  2. 删除器负责销毁动态对象: 对指针指向delete运算

    实际还是使用对象的析构函数销毁对象
  3. 删除器可以完成其他所需操作

删除器只对绑定的动态对象有效

 1#include <iostream>
 2#include <ostream>
 3#include <string>
 4#include <vector>
 5#include <memory>
 6
 7using std::cout;
 8using std::endl;
 9using std::string;
10using std::ostream;
11
12class Foo
13{
14  friend ostream &operator<<(ostream &os, const Foo &f);  
15public:
16  Foo(string _name): name(_name) {}
17  ~Foo() { cout << "Call ~Foo for " << *this << endl << endl; }
18private:
19  string name;
20};
21
22ostream &operator<<(ostream &os, const Foo &f)
23{
24  os << f.name;
25  return os;
26}
27
28void DeleteFoo(Foo *f)
29{
30  cout << "call " << __FUNCTION__ << " for " << *f << endl;
31  delete f; // 调用~Foo()
32}
33
34int main(int argc, const char * argv[]) {
35  Foo f("Kate");
36  auto p = new Foo("Peter");
37  std::shared_ptr<Foo> f2(p, DeleteFoo); // 为Peter绑定删除器
38
39  f2 = make_shared<Foo>("Mary");         // 为Peter调用删除器, 删除器调用析构函数
40
41  f2 = nullptr;                          // 为Mary调用析构函数
42
43  cout << "main finished.\n";
44  return 0;
45}                                        // main函数结束才为Kate调用析构函数

输出

call DeleteFoo for Peter
Call ~Foo for Peter

Call ~Foo for Mary

main finished.
Call ~Foo for Kate

善用shared_ptr机制: 使用删除器管理非动态对象

  1. shared_ptr指向非动态对象
  2. 销毁shared_ptr时,对管理对象调用删除器

示例

使用shared_ptr管理connection

销毁shared_ptr时,对connection调用end_connection: connection仍存在,可再次使用

1void end_connection(connection *p) { disconnect(*p); }
2
3void f(destination &d)
4{
5    connection c = connect(&d);
6    shared_ptr<connection> p(&c, end_connection); // 销毁p时会对c调用end_connection
7}

shared_ptr接管动态对象时, 为动态对象绑定删除器

reset

提供重载版本: 第一个参数的缺省值为nullptr,第二个参数的缺省值为delete

  1. 形参列表为空: 将shared_ptr置空

    如果需要销毁动态对象, 使用delete运算符

  2. 传入内置指针: 从内置指针接管动态对象

    免去显式转换

    如果需要销毁动态对象, 使用delete运算符

  3. 传入内置指针和删除器: 从内置指针接管动态对象, 并为该动态对象绑定删除器

    之后删除该动态对象时, 使用删除器

    联合管理同一动态对象的计数器和删除器(如有绑定)是共用的

1sp.reset();
2// =>
3// sp = nullptr;
4
5sp.reset(p);
6// =>
7// sp = shared_ptr<T>(p);
8
9sp.reset(p, d);

示例

 1#include <iostream>
 2#include <string>
 3#include <vector>
 4#include <memory>
 5
 6using std::cout;
 7using std::endl;
 8using std::string;
 9
10void DeleteString(string *ps)
11{
12    if (ps) {
13        cout << "Delete " << *ps << endl << endl;
14        delete ps;
15    }
16}
17
18void DeleteString1(string *ps)
19{
20    cout << "This is " << __FUNCTION__ << ": ";
21    DeleteString(ps);
22}
23
24void DeleteString2(string *ps)
25{
26    cout << "This is " << __FUNCTION__ << ": ";
27    DeleteString(ps);
28}
29
30int main(int argc, const char * argv[])
31{
32    auto p = new string("Hat");
33    auto p2 = new string("Shoe");
34    std::shared_ptr<string> sp(p, DeleteString1); // 为Hat绑定删除器DeleteString1
35    sp.reset(p2, DeleteString2);                  // 为Hat调用删除器DeleteString1; 为Shoe绑定删除器DeleteString2
36
37    auto sp2 = sp;
38    sp = nullptr;
39    cout << "main finished.\n\n";
40    return 0;
41}                                                 // 为Shoe调用删除器DeleteString2

输出

This is DeleteString1: Delete Hat

main finished.

This is DeleteString2: Delete Shoe

注意: 使用一个shared_ptr初始化另一个shared_ptr时, 传入删除器

P413提到了该操作

1shared_ptr<T> sp1(sp2, d);

想要探究sp2所指动态对象的销毁途径, 但无法正确执行该操作. 做了以下尝试, 皆不成:

  1. 只sp2拥有删除器

    1auto p = new Foo("Peter");
    2shared_ptr<Foo> sp1(p);
    3
    4shared_ptr<Foo> sp2(sp1, DeleteFoo);   // 报错: no known conversion from 'shared_ptr<Foo>' to 'std::nullptr_t'
    5
    6// 仅说明意图
    7sp2 = nullptr;
  2. sp1和sp2拥有相同的删除器

    1auto p = new Foo("Peter");
    2shared_ptr<Foo> sp1(p, DeleteFoo);     // 为Peter绑定删除器
    3
    4shared_ptr<Foo> sp2(sp1, DeleteFoo);   // 报错: no known conversion from 'shared_ptr<Foo>' to 'std::nullptr_t'
    
  3. sp2为移后源

    1auto p = new Foo("Peter");
    2shared_ptr<Foo> sp1(p);
    3
    4shared_ptr<Foo> sp2(std::move(sp1), DeleteFoo); // 报错: no known conversion from 'typename remove_reference<shared_ptr<Foo> &>::type' (aka 'std::shared_ptr<Foo>') to 'std::nullptr_t'