在开始之前,先定义一个为了测试用的MyObject类。

class MyObject
{
private:
    int m_Value = 0;
    int m_Data[10240]; // 这一坨是为了占空间
    std::shared_ptr<MyObject> m_Child;
public:
    MyObject(const int value)
    {
        m_Value = value;
    }

    int GetValue()
    {
        return m_Value;
    }

    void SetChild(std::shared_ptr<MyObject>& child)
    {
        m_Child = child;
    }
};

unique_ptr

unique_ptr只允许同一块堆内存被一个unique_ptr持有。代码上看起来是这样的。

std::unique_ptr<MyObject> up_obj(new MyObject(100));

//std::unique_ptr<MyObject> up_obj2(up_obj); // 报错 C2280

//std::unique_ptr<MyObject> up_obj3;
//up_obj3 = up_obj; // 报错 C2280

std::shared_ptr<MyObject> sp_obj(new MyObject(200));
// 将一个unique_ptr赋值给其它智能指针也是不行的
//std::shared_ptr<MyObject> sp_o = up_obj; // C2440
//std::unique_ptr<MyObject> up_fuck = sp_obj; // C2440

// 这样是可以编译通过的,但是运行时会出错
std::shared_ptr<MyObject> sppp(up_obj.get());

shared_ptr

这个类型的智能指针用起来的风格,就非常像Java了。

std::shared_ptr<MyObject> sp_obj(new MyObject(123));
std::shared_ptr<MyObject> sp_obj2(sp_obj);
std::shared_ptr<MyObject> sp_obj3 = sp_obj;
std::cout << "sp_obj value: " << sp_obj->GetValue() << " use count: " << sp_obj.use_count() << std::endl;

运行后内存中应该是这个样子的。

clipboard.png

shared_ptr是通过引用计数的方式来实现的,也就是说,它解决不了循环引用。

实验如下:
先写一个方法,里面构造了两个shared_ptr,因为MyObject对象里面有个shared_ptr成员变量,因此让这两个对象相互引用。

void testLoopRef() 
{
    std::shared_ptr<MyObject> sp_obj111(new MyObject(111));
    std::shared_ptr<MyObject> sp_obj999(new MyObject(999));

    sp_obj111->SetChild(sp_obj999);
    sp_obj999->SetChild(sp_obj111);
}

然后再将这个方法放到主函数中运行,端点执行,查看每一步的内存变化。

clipboard.png

内存中看起来应该是这个样子:

clipboard.png

weak_ptr

为了解决循环引用的问题,可以使用weak_ptr来搞。
我们将MyObject类,进行改造,把它的m_Child属性改成weak_ptr的。

class MyObject2
{
private:
    int m_Value = 0;
    int m_Data[10240];
    std::weak_ptr<MyObject2> m_Child;
public:
    MyObject2(const int value)
    {
        m_Value = value;
    }

    int GetValue()
    {
        return m_Value;
    }

    void SetChild(std::shared_ptr<MyObject2>& child)
    {
        m_Child = child;
    }
};

然后,再次使用和上面代码几乎一样的代码进行测试。

clipboard.png

总结

这里只是一个初步的,浅显的关于“用法”的学习探究过程的记录。因为还没有投入到实战中用过,所以也没有什么特别的心得体会和技巧分享给大家。

参考

智能指针(现代 C++)
如何:创建和使用 unique_ptr 实例
如何:创建和使用 shared_ptr 实例
如何:创建和使用共享 weak_ptr 实例


krosshj
152 声望16 粉丝

Developer, Gamer, Artist