1. 程式人生 > 實用技巧 >C++智慧指標

C++智慧指標

Smart Pointer

std::unique_ptr - single ownership

std::shared_ptr - shared ownership

std::weak_ptr - temp / no ownership


為什麼使用智慧指標?

void bar(Entity* e) {
    // who owns e?
    // How long is e's life cycle?
    // Should I delete e?
}

void foo() {
    Entity* e = new Entity();
    e->DoSomething();
    bar(e);
}

foo();
// out of scope, memory leak
void bar(std::unique_ptr<Entity> e) {
    // bar owns e
    // e will be automatically destoryed
}

void foo() {
    auto e = std::unique_ptr<Entity>();
    e->DoSomething();
    bar(std::move(e));
}

foo();
// no memory leak

1、建立unique_ptr

1 std::unique_ptr<Entity> e1 = new Entity();
//non-assignable 2 std::unique_ptr<Entity> e1(new Entity()); //OK 3 std::unique_ptr<Entity> e1 = std::make_unique<Entity>(); //preferred 4 auto e2 = std::make_unique<Entity>(); //preferred 5 std::unique_ptr<Entity> e2 = e1; //non-copyable 6 std::unique_ptr<Entity> e2 = std::move(e1); //
moveable, transfer ownership 7 foo(std::move(e1)); //transfer ownership

Example:

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <memory>
 4 #include <string>
 5 
 6 using namespace std;
 7 
 8 class Entity {
 9    public:
10     Entity() { puts("Entity created!"); }
11     ~Entity() { puts("Entity destoried!"); }
12 };
13 
14 void ex1() {
15     puts("------------");
16     puts("Entering ex1");
17     {
18         puts("Entering ex1::scope1");
19         auto e1 = make_unique<Entity>();
20         puts("Leaveing ex1::scope1");
21     }
22     puts("Entering ex1");
23 }
24 
25 void foo(unique_ptr<Entity>) {
26     puts("Entering foo");
27     puts("leaving  foo");
28 }
29 
30 void ex2() {
31     puts("------------");
32     puts("Entering ex2");
33     auto e1 = make_unique<Entity>();
34     foo(move(e1));
35     // e1 was destoried.
36     puts("Leaving ex2");
37 }
38 
39 int main(int argc, char const *argv[]) {
40     ex1();
41     ex2();
42     return 0;
43 }

2、unique_ptr的生命週期

建立shared_ptr

1 std::shared_ptr<Entity> e1 = std::make_shared<Entity>();  // preferred
2 std::shared_ptr<Entity> e1(new Entity());                 // OK
3 auto e1 = std::make_shared<Entity>();                     // preferred
4 std::shared_ptr<Entity> e2 = e1;             // copyable,use_count+1
5 std::shared_ptr<Entity> e2 = std::move(e1);  // moveable, use_count remains
6 foo(std::move(e1));                          // use_count remains
7 foo(e1);                                     // use_count+1

example:

#include <cstdio>
#include <iostream>
#include <memory>
#include <string>

using namespace std;

class Entity {
   public:
    Entity() { puts("Entity created!"); }
    ~Entity() { puts("Entity destoried!"); }
};

oid ex3() {
    puts("-------------");
    puts("Entering ex3");
    auto e1 = make_shared<Entity>();
    cout << e1.use_count() << endl;
    {
        puts("Entering ex3::scope1");
        auto e2 = e1;
        cout << e1.use_count() << endl;
        auto e3 = move(e2);
        cout << e1.use_count() << endl;
        puts("Leaving ex3:scope1");
    }
    cout << e1.use_count() << endl;
    puts("Leaving ex3");
}

int main(int argc, char const *argv[]) {
    // ex1();
    // ex2();
    ex3();
    return 0;
}

out:

shared_ptr的生命週期

在fun1中建立了shared_ptr,transfer給fun2後引用計數還是1,在func2中用多執行緒呼叫了fun3,fun4,fun5,shared給它們

小結:

1.儘量使用智慧指標而不是裸指標

2.優先使用unique_ptr

unique_ptr

正常情況下分配與釋放動態記憶體:

#include <iostream>
#include <memory>
#include <string>

using namespace std;

int main(void) 
{
     string *str = new(string("hello world"));
     delete str;   //需要手動去釋放
   return 0; }

使用智慧指標unique_ptr

unique_ptr<string> pointer(new string("hello world"));  
// pointer是一個棧變數,在棧變數被回收後動態記憶體也會被回收
cout << *pointer << '\n';