《深入理解C++11》笔记-智能指针unique_ptr、shared_ptr、weak_ptr

上一篇:《深入理解C++11》笔记-强类型枚举
本篇介绍C++11中新增的智能指针:unique_ptr、shared_ptr、weak_ptr。使用智能指针可以免于我们去主动管理内存,智能指针会自动释放内存:

class Example {
public:
    Example() { std::cout << "Example()" << std::endl; }
    ~Example() { std::cout << "~Example()" << std::endl; }
};

int main()
{
    {
        std::unique_ptr<Example> unique_p1(new Example());   // Example()
    }                                                        // ~Example()

    {
        std::shared_ptr<Example> shared_p1(new Example());   // Example()
    }                                                        // ~Example()

    return 0;
}

在智能指针的作用域结束时,会自动释放申请的内存。

unique_ptr

从命名上看,unique_ptr就是独有指针,这里的独有代表什么?我们来看一下例子:

std::unique_ptr<int> p1(new int(0));     // 指向int类型的智能指针
std::unique_ptr<int> p2 = p1;            // 编译失败,unique_ptr不能与其他指针共享同一份内存
std::shared_ptr<int> p3 = p1;            // 编译失败,unique_ptr不能与其他指针共享同一份内存

std::unique_ptr<int> p4 = std::move(p1); // 使用move函数,能够转移内存的所有权
std::shared_ptr<int> p5 = std::move(p4);

从上面的代码可以看到,unique_ptr独占了指向的内存空间,其他智能指针不能与之共享。当释放引用或离开作用域时,内存就会被释放:

class Example {
public:
    Example() { std::cout << "Example()" << std::endl; }
    ~Example() { std::cout << "~Example()" << std::endl; }
};

int main()
{
    std::unique_ptr<Example> p1(new Example());     // Example()
    p1.reset();                                     // ~Example(),释放引用,释放内存

    return 0;
}

shared_ptr

shared_ptr和unique_ptr不同,它运行多个shared_ptr共享一份内存:

std::shared_ptr<int> p1(new int(0));         // 指向int类型的智能指针
std::cout << p1.use_count() << std::endl;    // 1
std::shared_ptr<int> p2 = p1;                // 引用计数增加
std::cout << p1.use_count() << std::endl;    // 2

shared_ptr采用了引用计数的方式来计算有几个shared_ptr拥有该内存,通过use_count成员函数能够拿到引用计数总数。当引用计数为0,或则离开作用域时,内存就会被释放:

class Example {
public:
    Example() { std::cout << "Example()" << std::endl; }
    ~Example() { std::cout << "~Example()" << std::endl; }
};

int main()
{
    std::shared_ptr<Example> p1(new Example());     // Example()
    std::cout << p1.use_count() << std::endl;       // 1
    std::shared_ptr<Example> p2 = p1;
    std::cout << p1.use_count() << std::endl;       // 2
    p2.reset();                                     // 释放引用计数
    std::cout << p1.use_count() << std::endl;       // 1
    p1.reset();                                     // ~Example(),释放引用计数,计数为0,释放内存
    std::cout << p1.use_count() << std::endl;       // 0

    return 0;
}

weak_ptr
weak_ptr不能直接指向内存空间,只能指向shared_ptr:

class Example {
public:
    Example() { std::cout << "Example()" << std::endl; }
    ~Example() { std::cout << "~Example()" << std::endl; }
};

int main()
{
    std::weak_ptr<Example> weak_p1(new Example());               // 不能直接指向内存空间

    std::unique_ptr<Example> unique_p1(new Example()); 
    std::weak_ptr<Example> weak_p2 = unique_p1;                  // 不能指向unique_ptr

    std::shared_ptr<Example> shared_p1(new Example());
    std::weak_ptr<Example> weak_p3 = shared_p1;                    // 不占用引用计数
    std::cout << shared_p1.use_count() << std::endl;               // 1
    std::shared_ptr<Example> shared_p2 = shared_p1;
    std::cout << weak_p3.use_count() << std::endl;                 // 2,同样能获取引用计数

    std::shared_ptr<Example> shared_p3 = weak_p3.lock();           // lock返回shared_ptr对象
    std::cout << shared_p1.use_count() << std::endl;               // 3

    shared_p1.reset();
    shared_p2.reset();
    shared_p3.reset();

    if (!weak_p3.lock())                                          // 智能指针已经释放,weak_ptr.lock返回空指针
    {
        std::cout << "nullptr" << std::endl;
    }

    return 0;
}

weak_ptr指向shared_ptr对象,但是本身不占用引用计数;weak_ptr中的lock成员函数能够对shared_ptr智能指针进行有效性判断,防止空指针引用。

指针对象使用

现在我们了解了unique_ptr、shared_ptr、weak_ptr,再看看他们指向的对象应该怎么使用:

    std::unique_ptr<int> unique_p1(new int(0)); 
    std::cout << *unique_p1 << std::endl;                // 直接使用指针对象
    std::cout << *unique_p1.get() << std::endl;          // 通过get获取int*

    std::shared_ptr<int> shared_p1(new int(0));
    std::cout << *shared_p1 << std::endl;                // 直接使用指针对象
    std::cout << *shared_p1.get() << std::endl;          // 通过get获取int*

    std::weak_ptr<int> weak_p1 = shared_p1;
    std::cout << *weak_p1 << std::endl;                  // 不能直接使用
    std::cout << *weak_p1.get() << std::endl;            // 不能通过get获取int*
    std::cout << *weak_p1.lock() << std::endl;           // 通过lock获取shared_ptr对象,再使用对象
    std::cout << *weak_p1.lock().get() << std::endl;     // 通过lock获取shared_ptr对象,再使用get获取int*

下一篇:《深入理解C++11》笔记-常量表达式

猜你喜欢

转载自blog.csdn.net/WizardtoH/article/details/81016953
今日推荐