六一的部落格


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



独占所管理的动态对象:

  1. 拷贝构造函数为删除 delete
  2. 拷贝赋值运算符为删除 delete

移动构造函数和移动赋值运算符存在:

  1. 可以使用一个unique_ptr右值初始化另一个unique_ptr
  2. 可以使用一个unique_ptr右值为另一个unique_ptr赋值

创建unique_ptr: 不支持使用一个unique_ptr左值去初始化另一个unique_ptr

1unique_ptr<string> p1(new string("Stegosaurus"));
2unique_ptr<string> p2(p1); // 错误: p1是左值

赋值运算符


右侧运算对象可以是nullptr

如果unique_ptr不为空:

  1. 销毁unique_ptr所指动态对象
  2. 将unique_ptr置空
1u = nullptr;

右侧运算对象不能是另一个unique_ptr左值

1unique_ptr<string> p1(new string("Stegosaurus"));
2unique_ptr<string> p2;
3p2 = p1; // 错误: p1是左值

使用unique_ptr接管右值资源


移动构造函数接受一个unique_ptr右值

1unique_ptr<T> up((unique_ptr<T>(new T)));

移动赋值运算符的右操作数可以是一个unique_ptr右值

1auto p = new T;
2unique_ptr<T> up;
3up = unique_ptr<T>(p);

示例

 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 p1 = new Foo("Kate");
36    auto p2 = new Foo("Peter");
37
38    unique_ptr<Foo> up(p1);
39
40    up = unique_ptr<Foo>(p2);      // 为Kate调用析构函数
41
42    cout << "main finished.\n";
43    return 0;
44}                                  // main函数结束才为Peter调用析构函数

输出

Call ~Foo for Kate

main finished.
Call ~Foo for Peter

release操作: 交接动态对象的管理权限

如果unique_ptr不为空

  1. 返回指向动态对象的内置指针
  2. 将unique_ptr置空
1u.release();

要妥善处理release返回的动态对象


示例

  1. 用来初始化另一个unique_ptr
    1unique_ptr<string> p1(new string("Stegosaurus"));
    2unique_ptr<string> p2(p1.release());                 // 将所有权从p1移交给p2;p1变为空指针
    
  2. 销毁动态对象
    1unique_ptr<string> p(new string("Stegosaurus"));
    2delete p.release();                                  // 直接销毁p管理的动态对象
    

reset操作: 接管内置指针管理的动态对象

提供重载版本

  1. 形参列表为空, 或者传入nullptr

    如果unique_ptr非空, 销毁所指动态对象, 将其置空
  2. 接受一个内置指针
    • 如果unique_ptr非空, 销毁所指动态对象, 将其置空
    • 如果内置指针非空, unique_ptr接管内置指针所指动态对象
1up.reset();
2up.reset(nullptr);
3
4up.reset(p);

示例: 接管release操作返回的动态对象

1unique_ptr<string> p1(new string("Stegosaurus"));
2unique_ptr<string> p2(new string("Trex"));
3p1.reset(p2.release());                       // 如果p1非空, 销毁所指动态对象; p1接管release操作返回的动态对象; p2亦被置为空, 由release保证
4                                              // 释放p1管理的资源, 将p2所指动态对象的所有权移交给p1; 将p2置空: 这一系列操作实则等价于unique_ptr之间的赋值操作

返回一个unique_ptr

允许拷贝一个将要销毁的unique_ptr

允许使用一个将要销毁的unique_ptr为另一个unique_ptr赋值

  1. 返回一个unique_ptr

    1unique_ptr<int> clone(int p)
    2{
    3    return unique_ptr<int>(new int(p));
    4}
  2. 返回局部对象的拷贝

    1uniuqe_ptr<int> clone(int p)
    2{
    3    unique_ptr<int> ret(new int(p));
    4    return ret;
    5}

保证了unique_ptr所管理动态资源仍有效


注意: 使用一个unique_ptr初始化shared_ptr

P412提到了该操作

1shared_ptr<T> p(u);
  1. 不能使用一个unique_ptr左值初始化shared_ptr

    1auto p = new Foo("Peter");
    2unique_ptr<Foo> up(p);
    3
    4shared_ptr<Foo> sp(up); // 报错: no known conversion from 'unique_ptr<Foo>' to 'std::nullptr_t'
    
  2. 可以使用一个unique_ptr右值初始化一个shared_ptr

    会将unique_ptr置空

     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    unique_ptr<Foo> up(p);
    38    cout << "*up equals " << *up << endl;
    39
    40    shared_ptr<Foo> sp1(std::move(up));
    41
    42    if (up == nullptr) cout << "is null.\n";
    43
    44    cout << "main finished.\n";
    45    return 0;
    46}

    输出

    *up equals Peter
    is null.
    main finished.
    Call ~Foo for Peter

unique_ptr与删除器

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

需在定义unique_ptr对象时给出删除器类型


默认初始化

给出删除器类型

1unique_ptr<T, D> up;

直接初始化

  1. 绑定删除器
  2. 使用内置指针初始化, 绑定删除器
1unique_ptr<T, D> up(d);
2
3unique_ptr<T, D> up2(new T, d);

使用删除器管理非动态对象

1void end_connection(connection *p) { disconnect(*p); }
2
3void f(destination &d)
4{
5    connection c = connect(&d);
6    unique_ptr<connection, decltype(end_connection)*> p(&c, end_connection);
7}

智能指针: unique_ptr


独占所管理的动态对象:

  1. 拷贝构造函数为删除 delete
  2. 拷贝赋值运算符为删除 delete

移动构造函数和移动赋值运算符存在:

  1. 可以使用一个unique_ptr右值初始化另一个unique_ptr
  2. 可以使用一个unique_ptr右值为另一个unique_ptr赋值

创建unique_ptr: 不支持使用一个unique_ptr左值去初始化另一个unique_ptr

1unique_ptr<string> p1(new string("Stegosaurus"));
2unique_ptr<string> p2(p1); // 错误: p1是左值

赋值运算符


右侧运算对象可以是nullptr

如果unique_ptr不为空:

  1. 销毁unique_ptr所指动态对象
  2. 将unique_ptr置空
1u = nullptr;

右侧运算对象不能是另一个unique_ptr左值

1unique_ptr<string> p1(new string("Stegosaurus"));
2unique_ptr<string> p2;
3p2 = p1; // 错误: p1是左值

使用unique_ptr接管右值资源


移动构造函数接受一个unique_ptr右值

1unique_ptr<T> up((unique_ptr<T>(new T)));

移动赋值运算符的右操作数可以是一个unique_ptr右值

1auto p = new T;
2unique_ptr<T> up;
3up = unique_ptr<T>(p);

示例

 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 p1 = new Foo("Kate");
36    auto p2 = new Foo("Peter");
37
38    unique_ptr<Foo> up(p1);
39
40    up = unique_ptr<Foo>(p2);      // 为Kate调用析构函数
41
42    cout << "main finished.\n";
43    return 0;
44}                                  // main函数结束才为Peter调用析构函数

输出

Call ~Foo for Kate

main finished.
Call ~Foo for Peter

release操作: 交接动态对象的管理权限

如果unique_ptr不为空

  1. 返回指向动态对象的内置指针
  2. 将unique_ptr置空
1u.release();

要妥善处理release返回的动态对象


示例

  1. 用来初始化另一个unique_ptr
    1unique_ptr<string> p1(new string("Stegosaurus"));
    2unique_ptr<string> p2(p1.release());                 // 将所有权从p1移交给p2;p1变为空指针
    
  2. 销毁动态对象
    1unique_ptr<string> p(new string("Stegosaurus"));
    2delete p.release();                                  // 直接销毁p管理的动态对象
    

reset操作: 接管内置指针管理的动态对象

提供重载版本

  1. 形参列表为空, 或者传入nullptr

    如果unique_ptr非空, 销毁所指动态对象, 将其置空
  2. 接受一个内置指针
    • 如果unique_ptr非空, 销毁所指动态对象, 将其置空
    • 如果内置指针非空, unique_ptr接管内置指针所指动态对象
1up.reset();
2up.reset(nullptr);
3
4up.reset(p);

示例: 接管release操作返回的动态对象

1unique_ptr<string> p1(new string("Stegosaurus"));
2unique_ptr<string> p2(new string("Trex"));
3p1.reset(p2.release());                       // 如果p1非空, 销毁所指动态对象; p1接管release操作返回的动态对象; p2亦被置为空, 由release保证
4                                              // 释放p1管理的资源, 将p2所指动态对象的所有权移交给p1; 将p2置空: 这一系列操作实则等价于unique_ptr之间的赋值操作

返回一个unique_ptr

允许拷贝一个将要销毁的unique_ptr

允许使用一个将要销毁的unique_ptr为另一个unique_ptr赋值

  1. 返回一个unique_ptr

    1unique_ptr<int> clone(int p)
    2{
    3    return unique_ptr<int>(new int(p));
    4}
  2. 返回局部对象的拷贝

    1uniuqe_ptr<int> clone(int p)
    2{
    3    unique_ptr<int> ret(new int(p));
    4    return ret;
    5}

保证了unique_ptr所管理动态资源仍有效


注意: 使用一个unique_ptr初始化shared_ptr

P412提到了该操作

1shared_ptr<T> p(u);
  1. 不能使用一个unique_ptr左值初始化shared_ptr

    1auto p = new Foo("Peter");
    2unique_ptr<Foo> up(p);
    3
    4shared_ptr<Foo> sp(up); // 报错: no known conversion from 'unique_ptr<Foo>' to 'std::nullptr_t'
    
  2. 可以使用一个unique_ptr右值初始化一个shared_ptr

    会将unique_ptr置空

     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    unique_ptr<Foo> up(p);
    38    cout << "*up equals " << *up << endl;
    39
    40    shared_ptr<Foo> sp1(std::move(up));
    41
    42    if (up == nullptr) cout << "is null.\n";
    43
    44    cout << "main finished.\n";
    45    return 0;
    46}

    输出

    *up equals Peter
    is null.
    main finished.
    Call ~Foo for Peter

unique_ptr与删除器

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

需在定义unique_ptr对象时给出删除器类型


默认初始化

给出删除器类型

1unique_ptr<T, D> up;

直接初始化

  1. 绑定删除器
  2. 使用内置指针初始化, 绑定删除器
1unique_ptr<T, D> up(d);
2
3unique_ptr<T, D> up2(new T, d);

使用删除器管理非动态对象

1void end_connection(connection *p) { disconnect(*p); }
2
3void f(destination &d)
4{
5    connection c = connect(&d);
6    unique_ptr<connection, decltype(end_connection)*> p(&c, end_connection);
7}