1.智能指针

文章详细介绍了C++11中的三种智能指针:shared_ptr用于共享所有权,自动管理对象生命周期,避免内存泄露;unique_ptr拥有唯一所有权,不支持拷贝,确保资源只被一个智能指针控制;weak_ptr则用于解决循环引用问题,不增加对象引用计数,防止内存泄漏。示例代码展示了它们的使用方法和特性,包括多线程环境下的行为。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C++11中智能指针分为三种:shared_ptr、unique_ptr、weak_ptr. (auto_ptr:discard)。
智能指针的主要功能是为了防止指针所指向的对象已经释放,出现内存泄露,野指针等问题。


一、智能指针

1.shared_ptr

1.1 实现方式:
shared_ptr中会有两个基本成员指针:一个用于存储我们用于初始化该class 的指针。One returned When calling member function,such as get().
另一个指针指向一个数据控制块(control block)。其作用主要是用于管理对象,数据控制块主要包括指向shared_ptr 所指对象的计数器(用于判断对象是否需要delete),指向weak_ptr 所指对象的计数器(shared_ptr中包含weak_ptr成员对象),deleter ,allocator(用于所指向对象的内存分配释放)等。
1.2 使用

  • 初始化和 成员函数的使用
#include<iostream>
#include<memory>
using namespace std;

class Base
{
public:
    int a;
    Base(int k) :a(k) {}
    ~Base() {
        cout << "Base is going to destructor" << endl;
    }
};
int main() 
{
    // initial
    Base* p = new Base(1);
    //or auto sptr = make_shared<Base>(p);
    shared_ptr<Base> sptr(p);
    cout << "p =\t" << p << endl;
    cout << "sptr=\t" << sptr << endl;
    cout << "sptr.get()=\t" << sptr.get() << endl;
    
    // member functions
    // reset(), shared_ptr will call destructor function,when the number of count equal 0
    cout << "test reset,destructor" << endl;
    sptr.reset();
    cout << "after reset, sptr=\t" << sptr << endl;

    // swap()
    Base* p2 = new Base(1);
    shared_ptr<Base> sptr2(p2);
    cout << "sptr2=\t" << sptr2 << endl;
    sptr2.swap(sptr);
    cout << "after swap with sptr,sptr2=\t" << sptr2 << endl;
    cout << "after swap with sptr,p2=\t" << p2 << endl;
    //use_count
    shared_ptr<Base> sptr4(new Base(1));
    cout << "the number of point to obj =\t" << sptr4.use_count() << endl;
    sptr2 = sptr4;
    cout << "after copy to sptr2,the number of point to obj of sptr4=\t" << sptr4.use_count() << endl;
    cout << "after copy to sptr2,the number of point to obj of sptr2=\t" << sptr2.use_count() << endl;

    return 0;
}
/* 结果:
p =     0097EBD8
sptr=   0097EBD8
sptr.get()=     0097EBD8
// member function
//reset
test reset,destructor
Base is going to destructor
after reset, sptr=      00000000
// swap
sptr2=  00985828
after swap with sptr,sptr2=     00000000
after swap with sptr,p2=        00985828
//use_count
the number of point to obj =    1
after copy to sptr2,the number of point to obj of sptr4=        2
after copy to sptr2,the number of point to obj of sptr2=        2
Base is going to destructor
Base is going to destructor
*/
  • 多线程下 shared_ptr 共享指针计数器
#include <chrono>
#include <iostream>
#include <memory>
#include <mutex>
#include <thread>

using namespace std::chrono_literals;

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 print(const char* rem, std::shared_ptr<Base> const& sp)
{
    std::cout << rem << "\n\tget() = " << sp.get()
        << ", use_count() = " << sp.use_count() << '\n';
}

void thr(std::shared_ptr<Base> p)
{
    std::this_thread::sleep_for(987ms);
    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);
        print("Local pointer in a thread:", lp);
    }
}

int main()
{
    std::shared_ptr<Base> p = std::make_shared<Derived>();

    print("Created a shared Derived (as a pointer to Base)", p);

    std::thread t1{ thr, p }, t2{ thr, p }, t3{ thr, p };
    p.reset(); // release ownership from main

    print("Shared ownership between 3 threads and released ownership from main:", p);

    t1.join(); t2.join(); t3.join();

    std::cout << "All threads completed, the last one deleted Derived.\n";
}
/* result:
Base::Base()
Derived::Derived()
Created a shared Derived (as a pointer to Base)
        get() = 0098E3F4, use_count() = 1
Shared ownership between 3 threads and released ownership from main:
        get() = 00000000, use_count() = 0
Local pointer in a thread:
        get() = 0098E3F4, use_count() = 6
Local pointer in a thread:
        get() = 0098E3F4, use_count() = 4
Local pointer in a thread:
        get() = 0098E3F4, use_count() = 2
Derived::~Derived()
Base::~Base()
All threads completed, the last one deleted Derived.

*/

2.unique_ptr

unique_ptr 指针用于管理一个对象,同一时刻,只能有一个这样的智能指针指向该对象。当调用 operator=,reset()时, unique_ptr会将先前的指针置为empty。

#include <cassert>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <memory>
#include <stdexcept>

// helper class for runtime polymorphism demo below
struct B
{
    virtual ~B() = default;

    virtual void bar() { std::cout << "B::bar\n"; }
};

struct D : B
{
    D() { std::cout << "D::D\n"; }
    ~D() { std::cout << "D::~D\n"; }

    void bar() override { std::cout << "D::bar\n"; }
};

// a function consuming a unique_ptr can take it by value or by rvalue reference
std::unique_ptr<D> pass_through(std::unique_ptr<D> p)
{
    p->bar();
    return p;
}

int main()
{
    std::cout << "1) Unique ownership semantics demo\n";
    {
        // Create a (uniquely owned) resource
        std::unique_ptr<D> p = std::make_unique<D>();

        // Transfer ownership to `pass_through`,
        // which in turn transfers ownership back through the return value
        std::unique_ptr<D> q = pass_through(std::move(p));

        // p is now in a moved-from 'empty' state, equal to nullptr
        assert(!p);
    }
}
/*
1) Unique ownership semantics demo
D::D
D::bar
D::~D
*/

3.weak_ptr

weak_ptr 是基于 shared_ptr 实现的指针类型,但weak_ptr 的赋值并不会引起shared_ptr指针计数器的变化。可以用于解决成员指针shared_ptr 链式指向对象,构成一个环时,在当前函数栈执行完成进行析构时,造成的这两个指针计数器不会下降为0,资源永远不会释放的局面。

// 有A,B,C三个Node对象,对象的成员指针构成一个环状,在使用weak_ptr和shared_ptr时,对象会有不同的释放内存结果。
#include <iostream>
#include <memory>

class Node
{
    char id;
    std::weak_ptr<Node> wptr;
    std::shared_ptr<Node> sptr;
public:
    Node(char id) : id{ id } {}
    ~Node() { std::cout << "  '" << id << "' reclaimed\n"; }
    /*...*/
    void assign(std::weak_ptr<Node> p) { wptr = p; }
    void assign(std::shared_ptr<Node> p) { sptr = p; }
};

enum class shared { all, some };

void test_cyclic_graph(const shared x)
{
    auto A = std::make_shared<Node>('A');
    auto B = std::make_shared<Node>('B');
    auto C = std::make_shared<Node>('C');

    A->assign(B);
    B->assign(C);

    if (shared::all == x)
    {
        C->assign(A);
        std::cout << "All links are shared pointers";
    }
    else
    {
        C->assign(std::weak_ptr<Node>(A));
        std::cout << "One link is a weak_ptr";
    }
    /*...*/
    std::cout << "\nLeaving...\n";
}

int main()
{
    test_cyclic_graph(shared::some);
    test_cyclic_graph(shared::all); // produces a memory leak
}
/*
//当有一根指针是weak_ptr指针的时候,三个对象依次被析构,且因为weak_ptr是指向A的,所以在析构时从A开始,依次按照内部成员指针的连接顺序析构。
One link is a weak_ptr
Leaving...
  'A' reclaimed
  'B' reclaimed
  'C' reclaimed
  //当所有的指针都是shared_ptr指针的时候,没有任何析构函数被调用,出现内存泄露。
All links are shared pointers
Leaving...

*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值