C++ 智能指针 std::shared_ptr

本文详细介绍了C++中智能指针的概念,如何通过RAII机制避免内存泄漏,以及shared_ptr和unique_ptr的区别。通过示例代码展示了智能指针的get、reset成员函数的使用,并解释了多线程环境下智能指针的安全性。
摘要由CSDN通过智能技术生成

c++中智能指针中的“智能”可以简单的理解为自动释放内存,这样就可以避免内存泄漏。具体怎么避免内存?它是怎样释放内存的呢?

智能指针的实现是使用了RAII机制,即:资源获取即初始化。也就是说在对象构造的时候申请内存(资源),在对象生存周期结束的时候,在析构函数中释放内存。

智能指针也是一个对象,是对c语言原生指针的封装,当智能指针的生存周期结束时,他会在析构函数中自动把他指向的对象给销毁。

shared_ptr和unique_ptr的区别是它允许多个shared_ptr共享同一个对象。它的实现内部有一个引用计算用来记录,一共有多少个shared_ptr共享对象。这个对象什么时候销毁呢?直到没有shared_ptr占有这个对象,即引用计数为0的时候自动销毁对象。

也就是说一旦最后一个这样的shared_ptr被销毁,也就是一旦某个对象的引用计数变为0,这个对象会被自动销毁。

make_shared

一般使用make_shared来创建一个智能指针。

#include <iostream>
#include <memory>
 
struct C
{
  C(int i) : i(i) {} 
  int i;
};
 
int main()
{
    auto sp = std::make_shared<C>(12);
 
    std::cout << sp->i << '\n';
}

输出:

12

下面介绍一些常用的成员函数

get

返回共享对象的地址,返回值是一个指针。

#include <iostream>
#include <memory>
#include <string_view>
 
void output(std::string_view msg, int const* pInt)
{
    std::cout << msg << *pInt << " in " << pInt << "\n";
}
 
int main()
{
    int* pInt = new int(42);
    std::shared_ptr<int> pShared = std::make_shared<int>(42);
 
    output("Naked pointer ", pInt);
    // output("Shared pointer ", pShared); // compiler error
    output("Shared pointer with get() ", pShared.get());
 
    delete pInt;
}

输出:

Naked pointer 42 in 0x0000546
Shared pointer with get() 42 in 0x0000154

reset

 取消shared_ptr 对象与相关指针的关联,它将引用计数减少1,如果引用计数变为0,则删除对象。

#include <memory>
#include <iostream>
 
struct Foo {
    Foo(int n = 0) noexcept : bar(n) {
        std::cout << "Foo: constructor, bar = " << bar << '\n';
    }
    ~Foo() {
         std::cout << "Foo: destructor, bar = " << bar << '\n';
    }
    int getBar() const noexcept { return bar; }
private:
    int bar;
};
 
int main()
{
    std::shared_ptr<Foo> sptr = std::make_shared<Foo>(1);
    std::cout << "The first Foo's bar is " << sptr->getBar() << "\n";
 
    // 重置shared_ptr, 把它指向一个新的Foo对象
    // reset之后旧的Foo对象将会被销毁
    sptr.reset(new Foo);
    std::cout << "The second Foo's bar is " << sptr->getBar() << "\n";
}

输出:

Foo: constructor, bar = 1
The first Foo's bar is 1
Foo: constructor, bar = 0
Foo: destructor, bar = 1
The second Foo's bar is 0
Foo: destructor, bar = 0

接下来看一段演示代码,代码很简单,创建一个指向derived对象的shared_ptr,然后把它作为参数开启三个线程执行thr函数。

#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <mutex>
 
struct Base
{
    Base() { std::cout << "  Base::Base()\n"; }
    // Note: non-virtual destructor is OK here
    ~Base() { std::cout << "  Base::~Base()\n"; }
};
 
struct Derived: public Base
{
    Derived() { std::cout << "  Derived::Derived()\n"; }
    ~Derived() { std::cout << "  Derived::~Derived()\n"; }
};
 
void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(std::chrono::seconds(1));
    std::shared_ptr<Base> lp = p; // thread-safe, even though the
                                  // shared use_count is incremented
    {
        static std::mutex io_mutex;
        std::lock_guard<std::mutex> lk(io_mutex);
        std::cout << "local pointer in a thread:\n"
                  << "  lp.get() = " << lp.get()
                  << ", lp.use_count() = " << lp.use_count() << '\n';
    }
}
 
int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();
 
    std::cout << "Created a shared Derived (as a pointer to Base)\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    std::thread t1(thr, p), t2(thr, p), t3(thr, p);
    p.reset(); // release ownership from main
    std::cout << "Shared ownership between 3 threads and released\n"
              << "ownership from main:\n"
              << "  p.get() = " << p.get()
              << ", p.use_count() = " << p.use_count() << '\n';
    t1.join(); t2.join(); t3.join();
    std::cout << "All threads completed, the last one deleted Derived\n";
}

他的输出如下:

Base::Base()
  Derived::Derived()
Created a shared Derived (as a pointer to Base)
  p.get() = 0x2299b30, p.use_count() = 1
Shared ownership between 3 threads and released
ownership from main:
  p.get() = 0, p.use_count() = 0
local pointer in a thread:
  lp.get() = 0x2299b30, lp.use_count() = 5
local pointer in a thread:
  lp.get() = 0x2299b30, lp.use_count() = 3
local pointer in a thread:
  lp.get() = 0x2299b30, lp.use_count() = 2
  Derived::~Derived()
  Base::~Base()
All threads completed, the last one deleted Derived
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值